diff --git a/.gitignore b/.gitignore index f3eadad..2672821 100644 --- a/.gitignore +++ b/.gitignore @@ -210,4 +210,6 @@ __marimo__/ node_modules/ .venv/ .env -.envrc \ No newline at end of file +.envrc + +.vscode \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index c5f3f6b..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "java.configuration.updateBuildConfiguration": "interactive" -} \ No newline at end of file diff --git a/README.md b/README.md index 2086b38..2e4e3e3 100644 --- a/README.md +++ b/README.md @@ -5,20 +5,29 @@ OpenBinding is a QoS-aware service composition gateway and solver engine framewo ## 🏗️ Architecture ```mermaid -graph TD - User[User / Frontend] -->|HTTP POST /v1/solve| Gateway[OpenBinding Gateway] - Gateway -->|1. Validate General Schema| Schema[General QoS Schema] - Gateway -->|2. Validate Specialization| Spec[Specialization Schema] - Gateway -->|3. Route Request| Router{Router} - - Router -->|engine_id=minizinc-csp| MZ[MiniZinc CSP Engine] - Router -->|engine_id=random-search| RS[Random Search Engine] - - MZ -->|Solve via Gecode| Solution - RS -->|Solve via Random Heuristic| Solution - - Solution --> Gateway - Gateway -->|HTTP 200| User +flowchart TD + U[User / Frontend]:::client + + U -->|HTTP POST /v1/solve| G[OpenBinding Gateway]:::gateway + + G --> V0[Validate request envelope]:::step + V0 --> V1[Validate basic composition schema]:::schema + V1 --> R{Root router: route by engine_id}:::router + + R -->|minizinc-csp| SZ_MZ[Validate specialization schema: MiniZinc]:::schema + R -->|random-search| SZ_RS[Validate specialization schema: Random Search]:::schema + R -->|many-heuristic| SZ_MH[Validate specialization schema: Many-Heuristic]:::schema + + SZ_MZ --> MZ[MiniZinc CSP engine]:::engine + SZ_RS --> RS[Random Search engine]:::engine + SZ_MH --> MH[Many-Heuristic engine]:::engine + + MZ -->|solve| SOL[(Solution)]:::solution + RS -->|solve| SOL + MH -->|solve| SOL + + SOL --> G + G -->|HTTP 200 result| U ``` ## đź§© Components @@ -40,6 +49,11 @@ graph TD * Uses random search. * Best for exploring large solution spaces. +4. **Many-Heuristic Engine** (`engines/many-heuristic`): + * Java service (extends Random Search). + * Specialized for **Many-Objective** problems (3+ objectives). + * Returns a **Pareto front** of non-dominated solutions. + 4. **Frontend** (`frontend`): * React + Vite web UI for modeling and submitting problems. * Multi-page SPA with professional design inspired by modern developer tools. @@ -56,6 +70,7 @@ OpenBinding validates incoming requests against two schema layers: 1. **General schema** (engine-agnostic): - JSON Schema (structural validation): `schemas/general/schema.json` + - Visual model (Mermaid): `schemas/general/schema.mermaid` - Specification / semantics (human-readable): `schemas/general/schema.specification.md` The specification document explains the intent and semantics behind the JSON Schema, including: @@ -67,6 +82,14 @@ OpenBinding validates incoming requests against two schema layers: 2. **Specialization schemas** (engine-specific constraints): - `schemas/specializations/minizinc-csp.schema.json` - `schemas/specializations/random-search.schema.json` + - `schemas/specializations/many-heuristic.schema.json` + + Specializations can also include a visual model in Mermaid format (recommended): + - `schemas/specializations/minizinc-csp.schema.mermaid` + - `schemas/specializations/random-search.schema.mermaid` + - `schemas/specializations/many-heuristic.schema.mermaid` + + Mermaid models are used by the frontend **Schema Explorer** in the **Model** tab. If a specialization does not provide `.schema.mermaid`, the JSON schema workflow remains fully functional. Example payloads that follow these schemas live in `examples/`. @@ -89,6 +112,7 @@ Example payloads that follow these schemas live in `examples/`. * **Gateway API**: [http://localhost:8000/docs](http://localhost:8000/docs) * **MiniZinc Engine**: Port 3000 (Internal) * **Random Search Engine**: Port 8081 (Internal) + * **Many-Heuristic Engine**: Port 8082 (Internal) 2. **Stop the Stack**: ```bash @@ -198,6 +222,14 @@ curl -X POST "http://localhost:8000/v1/solve" \ See `examples/` directory for sample payloads. +## đź§­ Engine Integration Guide + +If you are adding a new engine, see [docs/ENGINE_INTEGRATION_GUIDE.md](docs/ENGINE_INTEGRATION_GUIDE.md). + +## 🤝 Contributing + +See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for branch and PR rules. + ## đź“„ License This project is licensed under the **Creative Commons Attribution 4.0 International (CC BY 4.0)**. diff --git a/docker-compose.yml b/docker-compose.yml index 39a1149..8ac869f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,6 +15,7 @@ services: - PYTHONPATH=/app/src - ENGINE_MINIZINC_URL=http://engine-minizinc:3000 - ENGINE_RANDOM_SEARCH_URL=http://engine-random-search:8080 + - ENGINE_MANY_HEURISTIC_URL=http://engine-many-heuristic:8080 healthcheck: test: ["CMD", "curl", "-fsS", "http://localhost:8000/health"] interval: 10s @@ -26,6 +27,8 @@ services: condition: service_healthy engine-random-search: condition: service_healthy + engine-many-heuristic: + condition: service_healthy engine-minizinc: build: @@ -53,6 +56,19 @@ services: retries: 5 start_period: 30s + engine-many-heuristic: + build: + context: ./engines/many-heuristic + dockerfile: Dockerfile + ports: + - "8082:8080" + healthcheck: + test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"] + interval: 10s + timeout: 3s + retries: 5 + start_period: 30s + frontend: build: context: ./frontend @@ -64,3 +80,9 @@ services: depends_on: gateway: condition: service_healthy + healthcheck: + test: ["CMD", "curl", "-fsS", "http://localhost/"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 0000000..f0bc080 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,35 @@ +# Contributing + +Thanks for contributing to OpenBinding. + +## Branching model + +- Default branches: `develop` and `main`. +- Always create new branches from `develop`. +- Open pull requests into `develop`. +- Admin will merge `develop` into `main` when appropriate. + +## Workflow + +1. Create a feature branch from `develop`: + + ```bash + git checkout develop + git pull + git checkout -b feature/my-change + ``` + +2. Make changes with tests and documentation updates as needed. + +3. Push the branch and open a PR targeting `develop`. + +4. Address review feedback and keep the branch up to date with `develop`. All PRs must pass CI checks before merging. + +## Expectations + +- Keep changes focused and well tested. +- Update docs when behavior changes. +- Follow existing coding conventions and linting rules. +- Document the rationale for non-trivial changes in the PR description. If possible, create a small video demo of the change in action. +- Be responsive to review feedback and iterate on the PR until it meets the standards for merging. Each PR should be a self-contained unit of work that can be easily reviewed and understood. +- All PRs must be reviewed and approved by at least one other contributor before merging. This ensures code quality and knowledge sharing across the team. diff --git a/docs/ENGINE_INTEGRATION_GUIDE.md b/docs/ENGINE_INTEGRATION_GUIDE.md new file mode 100644 index 0000000..90233a4 --- /dev/null +++ b/docs/ENGINE_INTEGRATION_GUIDE.md @@ -0,0 +1,176 @@ +# Engine integration guide + +This guide explains how to add a new engine to the OpenBinding gateway. It covers schema specialization, validation hooks, routing, and tests. + +## Overview + +The gateway validates incoming instances in stages and then routes them to the selected engine. + +Validation stages: +1. General schema +2. Specialization schema +3. General semantic rules +4. Engine semantic rules + +Engines integrate through the gateway plugin interface and a specialization schema. + +## Required artifacts + +1. Engine plugin (gateway): implement `EngineValidationPlugin`. +2. Specialization schema: `schemas/specializations/.schema.json`. +3. Specialization model (recommended): `schemas/specializations/.schema.mermaid`. +4. Engine URL in registry + env wiring. +5. Tests for validation and transformation. + +## Step-by-step + +### 1) Add a specialization schema + +Create a specialization schema under `schemas/specializations/`. + +### 1.1) Add a specialization model (recommended) + +To enable visual exploration in the frontend **Schema Explorer** (`JSON | Model` tabs), add a Mermaid model next to your specialization schema: + +- Path: `schemas/specializations/.schema.mermaid` +- Naming must match your engine id exactly (``) + +The Mermaid model is optional, but strongly recommended for maintainability and onboarding. + +If the file is missing, the frontend will show **Model not available** while keeping JSON schema validation and all engine workflows fully operational. + +#### Good practices + +- Keep JSON and Mermaid aligned conceptually (same constraints/capabilities). +- Keep node/edge labels stable and meaningful across versions. +- Prefer modular Mermaid subgraphs for large models. +- Update both files in the same PR when constraints change. +- Avoid changing `` naming once released, to prevent schema/model mismatch. + + +## Engine options defaults (Playground) + +The frontend Playground can prefill the `options` object depending on the selected engine. +To support this, the gateway exposes engine-level defaults at: + +- `GET /v1/engines/{engine_id}/options/defaults` + +If the engine has no options, the endpoint returns an empty JSON object: `{}`. + +### How to define defaults + +Defaults are defined in the gateway engine plugin by implementing `get_default_options()`. +Example: + +- Return `{}` if your engine does not accept any options. +- Return a JSON object with the gateway defaults (e.g. `{ "iterations_count": 1000 }`) if your engine supports options. + +### 2) Implement the engine plugin + +Create a new plugin in `openbinding-gateway/src/openbinding_gateway/validation/engine_plugins/`: + +```python +from typing import Any, Dict, List, Tuple +import httpx +from .base import EngineValidationPlugin +from ...models.api import ValidationViolation + +class MyEnginePlugin(EngineValidationPlugin): + async def check_engine_health(self, base_url: str, client: httpx.AsyncClient) -> bool: + resp = await client.get(f"{base_url.rstrip('/')}/health") + return resp.status_code == 200 + + def get_capabilities(self) -> Dict[str, Any]: + return { + "qos_features_supported": ["*"], + "composition_nodes_supported": ["TASK", "SEQ"], + "objective_types_supported": ["weighted_sum"], + "constraints_supported": ["attribute_bound"], + "schema_version": "v1", + } + + def get_specialization_schema_path(self) -> str: + # Uses SCHEMAS_DIR if available + # e.g. /app/schemas/specializations/my-engine.schema.json + ... + + def validate_semantics(self, instance: Dict[str, Any]) -> List[ValidationViolation]: + violations: List[ValidationViolation] = [] + # Add engine-specific invariants here + return violations + + def transform_request(self, instance: Dict[str, Any], options: Dict[str, Any] = {}) -> Tuple[Dict[str, Any], List[str]]: + # Map general instance to engine request payload + return {"instance": instance, "options": options}, [] + + def transform_response(self, engine_response: Dict[str, Any], original_request: Dict[str, Any]) -> Dict[str, Any]: + # Map engine response to gateway solution format + return engine_response +``` + +### 3) Register the plugin and URL + +Add the plugin to `EngineRegistry`: + +- File: `openbinding-gateway/src/openbinding_gateway/registry/engine.py` +- Add env var for the engine URL (e.g. `ENGINE_MY_ENGINE_URL`). +- Register the plugin in the initialization block. + +Example: + +```python +from ..validation.engine_plugins.my_engine import MyEnginePlugin + +_engine_urls = { + "my-engine": os.getenv("ENGINE_MY_ENGINE_URL", "http://engine-my:1234"), +} + +EngineRegistry.register("my-engine", MyEnginePlugin()) +``` + +### 4) Ensure schema endpoints work + +The gateway exposes: + +- `/v1/schemas/general` +- `/v1/schemas/general/model` +- `/v1/schemas/` +- `/v1/schemas//model` + +Your specialization schema must exist and be discoverable via `SCHEMAS_DIR`. +Your specialization model should follow the same directory and naming convention to be discoverable by the `/model` endpoint. + +### 5) Add tests + +Recommended tests: + +- Schema and semantic validation: `openbinding-gateway/tests/test_validation_comprehensive.py` +- Plugin request/response transformation: `openbinding-gateway/tests/test_plugin_transformation.py` +- Integration tests via docker compose (if the engine is available) + +### 6) Wire docker compose (if needed) + +Add the engine service to `docker-compose.yml` and expose the engine URL to the gateway: + +```yaml +environment: + - ENGINE_MY_ENGINE_URL=http://engine-my:1234 +``` + +## Validation expectations + +The gateway uses schema defaults and semantic checks before engine-specific validation. If your engine depends on implicit rules, enforce them in `validate_semantics`. + +Common checks: + +- Unsupported composition nodes +- Unsupported constraint types or objective types +- Missing candidates or missing QoS values +- Attribute bounds on missing features + +## Troubleshooting + +- Check `/v1/engines` to confirm the engine is registered and reachable. +- Use `/v1/analyze` for validation errors and warnings. +- Ensure `SCHEMAS_DIR` resolves to the folder containing your specialization schema. +- If the Model tab shows unavailable, confirm `.schema.mermaid` exists under `schemas/specializations/` and matches engine id naming exactly. diff --git a/engines/many-heuristic/.classpath b/engines/many-heuristic/.classpath new file mode 100644 index 0000000..18c4786 --- /dev/null +++ b/engines/many-heuristic/.classpath @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engines/many-heuristic/.gitignore b/engines/many-heuristic/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/engines/many-heuristic/.gitignore @@ -0,0 +1 @@ +/target diff --git a/engines/many-heuristic/.project b/engines/many-heuristic/.project new file mode 100644 index 0000000..92ec78a --- /dev/null +++ b/engines/many-heuristic/.project @@ -0,0 +1,40 @@ + + + ManyObjectivesQoSawareCWSBinding + + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.wst.common.project.facet.core.nature + + + + 1768938301184 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/engines/many-heuristic/.settings/org.eclipse.core.resources.prefs b/engines/many-heuristic/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..6377efd --- /dev/null +++ b/engines/many-heuristic/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +encoding//src/main/java=ISO-8859-1 +encoding//src/test/java=ISO-8859-1 +encoding/=ISO-8859-1 diff --git a/engines/many-heuristic/.settings/org.eclipse.jdt.apt.core.prefs b/engines/many-heuristic/.settings/org.eclipse.jdt.apt.core.prefs new file mode 100644 index 0000000..d4313d4 --- /dev/null +++ b/engines/many-heuristic/.settings/org.eclipse.jdt.apt.core.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.apt.aptEnabled=false diff --git a/engines/many-heuristic/.settings/org.eclipse.jdt.core.prefs b/engines/many-heuristic/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..6a09005 --- /dev/null +++ b/engines/many-heuristic/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.processAnnotations=disabled +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/engines/many-heuristic/.settings/org.eclipse.m2e.core.prefs b/engines/many-heuristic/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/engines/many-heuristic/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/engines/many-heuristic/.settings/org.eclipse.wst.common.project.facet.core.xml b/engines/many-heuristic/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..bc0009a --- /dev/null +++ b/engines/many-heuristic/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,4 @@ + + + + diff --git a/engines/many-heuristic/Dockerfile b/engines/many-heuristic/Dockerfile new file mode 100644 index 0000000..2ea4324 --- /dev/null +++ b/engines/many-heuristic/Dockerfile @@ -0,0 +1,14 @@ +FROM maven:3.8-openjdk-8 as builder +WORKDIR /app +COPY pom.xml . +COPY src ./src +# COPY lib ./lib # No lib present or empty +RUN mvn package -DskipTests + +FROM eclipse-temurin:8-jre +WORKDIR /app +RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/* +COPY --from=builder /app/target/ManyHeuristicQoSawareCWSBinding-0.0.1-SNAPSHOT.jar app.jar +COPY --from=builder /app/target/dependency /app/dependency +EXPOSE 8080 +CMD ["java", "-cp", "app.jar:dependency/*", "es.us.isa.qosawarewsbinding.api.Server"] diff --git a/engines/many-heuristic/data/pruebatonta.txt b/engines/many-heuristic/data/pruebatonta.txt new file mode 100644 index 0000000..64f9bac --- /dev/null +++ b/engines/many-heuristic/data/pruebatonta.txt @@ -0,0 +1,111 @@ +%#============================= HEADER ======================================# +% This file contains an instance of the QoS-Aware Web Services Composition Problem +% FILE: pruebatonta.txt +% Created by: José Antonio Parejo Mestre +% Thu Mar 27 12:58:42 CET 2014 +% ---------------------- +% Problem Statistics: +% ---------------------- +% Number of activities: 4 +% Number of Candidate Services: 9 +% Number of Constraints: 0 +%#======================= COMPOSITION STRUCTURE =============================# +% Abstract Services: +%---------------------- +2 +t2 +t1 +% CompositionStructure: +%---------------------- +SEC[ + + BRANCH(0.6;0.4;)[ + SEC[t1, + ] + , + SEC[ + + LOOP(4000)[t2, + ] + , + ] + , + ] +, +] +%#======================= QOS MODEL =============================# +QoSModel{ + Properties{ + Availability:POSITIVE€Double[0.0,1.0] + Security:POSITIVE€Double[0.0,1.0] + ExecTime:NEGATIVE€Double[0.0,1.0] + Cost:NEGATIVE€Double[0.0,1.0] + Reliability:POSITIVE€Double[0.0,1.0] + } + AggregationFunctions( + Availability{ + Loop:PRODUCT + Branch:SUM + Flow:PRODUCT + Sequence:PRODUCT + } + Security{ + Loop:MIN + Branch:SUM + Flow:MIN + Sequence:MIN + } + ExecTime{ + Loop:SUM + Branch:SUM + Flow:MAX + Sequence:SUM + } + Cost{ + Loop:SUM + Branch:SUM + Flow:SUM + Sequence:SUM + } + Reliability{ + Loop:PRODUCT + Branch:SUM + Flow:PRODUCT + Sequence:PRODUCT + } + ) + Weights( + Availability:0.2 + Security:0.1 + ExecTime:0.2 + Cost:0.3 + Reliability:0.2 + ) +} +%#======================= CANDIDATE SERVICES =============================# +------------------------ +t2 +------------------------ +s23(Availability:0.5999999999999999,Security:0.24999999999999994,ExecTime:0.6666666666666666,Cost:0.7499999999999999,Reliability:0.0,) +s22(Availability:0.0,Security:1.0,ExecTime:0.0,Cost:1.0,Reliability:0.0,) +s21(Availability:0.0,Security:1.0,ExecTime:1.0,Cost:0.0,Reliability:1.0,) +------------------------ +t4 +------------------------ +s42(Availability:1.0,Security:0.0,ExecTime:0.33333333333333337,Cost:0.8749999999999999,Reliability:0.0,) +s41(Availability:0.0,Security:1.0,ExecTime:1.0,Cost:0.0,Reliability:1.0,) +------------------------ +t1 +------------------------ +s12(Availability:0.8,Security:1.0,ExecTime:0.8666666666666666,Cost:0.625,Reliability:0.0,) +s11(Availability:0.0,Security:1.0,ExecTime:0.0,Cost:1.0,Reliability:0.0,) +------------------------ +t3 +------------------------ +s32(Availability:1.0,Security:0.0,ExecTime:0.33333333333333337,Cost:0.8749999999999999,Reliability:0.0,) +s31(Availability:0.0,Security:1.0,ExecTime:1.0,Cost:0.0,Reliability:1.0,) +------------------------ +%#======================= CONSTRAINTS =============================# +0 +% ---------------------- +% ---------------------- diff --git a/engines/many-heuristic/pom.xml b/engines/many-heuristic/pom.xml new file mode 100644 index 0000000..0d57a13 --- /dev/null +++ b/engines/many-heuristic/pom.xml @@ -0,0 +1,55 @@ + + 4.0.0 + es.us.isa + ManyHeuristicQoSawareCWSBinding + 0.0.1-SNAPSHOT + + ISO-8859-1 + + + + commons-math + commons-math + 1.2 + + + com.google.code.gson + gson + 2.8.9 + + + junit + junit + 4.12 + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + + + org.apache.maven.plugins + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory}/dependency + + + + + + + \ No newline at end of file diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/AbstractWebService.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/AbstractWebService.java new file mode 100644 index 0000000..e7cc175 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/AbstractWebService.java @@ -0,0 +1,60 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding; + +import java.io.Serializable; + +/** + * + * @author japarejo + */ +public class AbstractWebService implements StructuralComponent, Serializable { + private String name; + public AbstractWebService(String name) + { + this.name=name; + } + + @Override + public String toString() + { + return name; + } + + + public String toStructuralString(String prefix) { + return prefix+name; + } + + public boolean isEmpty() { + return false; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AbstractWebService other = (AbstractWebService) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/Branch.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/Branch.java new file mode 100644 index 0000000..be05462 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/Branch.java @@ -0,0 +1,140 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * + * @author japarejo + */ +public class Branch implements CompositeStructuralComponent { + + protected Map branches; + protected List subComponents; + public Branch() + { + branches=new HashMap(); + subComponents=new LinkedList(); + } + + + public List getSubComponents() { + return subComponents; + } + + public void addBranch(StructuralComponent body, Double probability) + { + /*double scalingFactor=1.0/(1.0+probability.doubleValue()); + Double auxProbability=null; + for(StructuralComponent branch:branches.keySet()) + { + auxProbability=branches.get(branch); + branches.put(branch,auxProbability.doubleValue()*scalingFactor); + } + if(subComponents.size()==0) + branches.put(body,1.0); + else*/ + branches.put(body, probability); + subComponents.add(body); + } + + public void removeBrach(StructuralComponent body) + { + if(hasBranch(body)) + { + Double probability=branches.get(body); + branches.remove(body); + subComponents.remove(body); + if(probability.doubleValue()!=1.0) + { + double scalingFactor=1.0/(1.0-probability.doubleValue()); + for(StructuralComponent branch:branches.keySet()) + { + probability=branches.get(branch); + branches.put(branch,probability.doubleValue()*scalingFactor); + } + } + } + } + + public int numberOfBranches() + { + return subComponents.size(); + } + + private boolean hasBranch(StructuralComponent body) { + return subComponents.contains(body); + } + + + public Double getBranchProbability(StructuralComponent body) + { + Double result=new Double(0); + if(hasBranch(body)) + result=branches.get(body); + return result; + } + + + public Double getPonderation(StructuralComponent subcomponent) { + return getBranchProbability(subcomponent); + } + + + public String toStructuralString(String prefix) { + String newline = System.getProperty("line.separator"); + StringBuffer buffer=new StringBuffer(prefix+"BRANCH("); + for(StructuralComponent subComponent:subComponents) + buffer.append(branches.get(subComponent)+";"); + buffer.append(")["+newline); + String myprefix=prefix+" "; + for(StructuralComponent subComponent:subComponents) + buffer.append(subComponent.toStructuralString(myprefix)+newline+prefix+","+newline); + buffer.append(prefix+"]"); + return buffer.toString(); + } + + @Override + public String toString() + { + return toStructuralString(""); + } + + + public boolean isEmpty() { + boolean result=true; + for(StructuralComponent branch:subComponents){ + if(!branch.isEmpty()){ + result=false; + break; + } + } + return result; + } + + /*@Override + public void buildEvaluationMap(Map, Double> evaluationMap, Double currentValue) { + StructuralComponent component=null; + double probability=0; + for(String branchname:branches.keySet()) + { + component=branches.get(branchname); + probability=probabilities.get(branchname); + if(component instanceof CompositeStructuralComponent) + ((CompositeStructuralComponent)component).buildEvaluationMap(evaluationMap, probability*currentValue.doubleValue()); + else{ + List services=new ArrayList(1); + services.add((AbstractWebService)component); + evaluationMap.put(services,currentValue); + } + } + }*/ + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/CompositeStructuralComponent.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/CompositeStructuralComponent.java new file mode 100644 index 0000000..662d435 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/CompositeStructuralComponent.java @@ -0,0 +1,19 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding; + +import java.util.List; + +/** + * + * @author japarejo + */ +public interface CompositeStructuralComponent extends StructuralComponent { + + public List getSubComponents(); + public Double getPonderation(StructuralComponent subcomponent); + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/ConcreteWebService.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/ConcreteWebService.java new file mode 100644 index 0000000..85403fe --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/ConcreteWebService.java @@ -0,0 +1,53 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import es.us.isa.qosawarewsbinding.qos.QoSProperty; + +/** + * + * @author japarejo + */ +public class ConcreteWebService implements Serializable { + private String name; + private AbstractWebService abstractWebService; + protected Map qosmodel; + + + public ConcreteWebService(String name, AbstractWebService aws) + { + this.name=name; + this.abstractWebService=aws; + qosmodel=new HashMap(); + } + + public Object getQoSValue(QoSProperty property){ + return qosmodel.get(property); + } + + public void setQoSValue(QoSProperty property, Object value){ + qosmodel.put(property, value); + } + + public String getName() { + return name; + } + + public AbstractWebService getAbstractWebService() { + return abstractWebService; + } + + @Override + public String toString() + { + return name; + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/EmptyComponent.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/EmptyComponent.java new file mode 100644 index 0000000..3993d07 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/EmptyComponent.java @@ -0,0 +1,31 @@ +package es.us.isa.qosawarewsbinding; + +import java.io.Serializable; + +/** + * A no-op structural component representing an "ELEMENT" node in the + * composition. + * It is used for branches that do nothing (e.g., "skip" branches). + */ +public class EmptyComponent implements StructuralComponent, Serializable { + + private String id; + + public EmptyComponent(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + @Override + public String toStructuralString(String prefix) { + return prefix + "ELEMENT(" + id + ")"; + } + + @Override + public boolean isEmpty() { + return false; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/Flow.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/Flow.java new file mode 100644 index 0000000..e339aeb --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/Flow.java @@ -0,0 +1,67 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding; + +import java.util.List; + +/** + * + * @author japarejo + */ +public class Flow implements CompositeStructuralComponent { + + private List subcomponents; + + public Flow() { + subcomponents = new java.util.LinkedList(); + } + + public List getSubComponents() { + return subcomponents; + } + + + public Double getPonderation(StructuralComponent subcomponent) { + return 1.0; + } + + + public String toStructuralString(String prefix) { + String newline = System.getProperty("line.separator"); + StringBuffer buffer=new StringBuffer(prefix+"FLOW["+newline); + String myprefix=prefix+" ||=>"; + for(StructuralComponent subComponent:subcomponents) + buffer.append(subComponent.toStructuralString(myprefix)+","); + buffer.append("]"); + return buffer.toString(); + } + + public boolean isEmpty() { + boolean result=true; + for(StructuralComponent branch:subcomponents){ + if(!branch.isEmpty()){ + result=false; + break; + } + } + return result; + } + + /*@Override + public void buildEvaluationMap(Map, Double> evaluationMap, Double currentValue) { + List services=new LinkedList(); + for(StructuralComponent component:subcomponents) + { + if(component instanceof AbstractWebService) + { + services.add((AbstractWebService)component); + }else + ((CompositeStructuralComponent)component).buildEvaluationMap(evaluationMap,currentValue); + } + if(services.size()>0) + evaluationMap.put(services, currentValue); + }*/ +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/Loop.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/Loop.java new file mode 100644 index 0000000..04c7b56 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/Loop.java @@ -0,0 +1,98 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding; + +import java.util.LinkedList; +import java.util.List; + +/** + * + * @author japarejo + */ +public class Loop implements CompositeStructuralComponent { + + private int averageNumberOfIterations; + protected List subComponents; + public Loop(int averageNumberOfIterations) + { + this(averageNumberOfIterations,null); + } + public Loop(int averageNumberOfIterations, StructuralComponent component){ + this.averageNumberOfIterations=averageNumberOfIterations; + subComponents=new LinkedList(); + if(component!=null) + subComponents.add(component); + } + + + public List getSubComponents() { + return subComponents; + } + + public int getAverageNumberOfIterations() { + return averageNumberOfIterations; + } + + public void setAverageNumberOfIterations(int averageNumberOfIterations) { + this.averageNumberOfIterations = averageNumberOfIterations; + } + + + public Double getPonderation(StructuralComponent subcomponent) { + return (double)averageNumberOfIterations; + } + + + public String toStructuralString(String prefix) { + String newline = System.getProperty("line.separator"); + StringBuffer buffer=new StringBuffer(prefix+"LOOP("+averageNumberOfIterations+")["); + String myprefix=prefix+" "; + if(subComponents.size()>0) + { + if(!(subComponents.get(0) instanceof AbstractWebService)) + buffer.append(newline); + } + for(StructuralComponent subComponent:subComponents){ + if(subComponent instanceof CompositeStructuralComponent) + buffer.append(newline+subComponent.toStructuralString(myprefix)+newline+prefix+","); + else + buffer.append(subComponent.toStructuralString("")+","); + } + buffer.append(newline+prefix+"]"); + return buffer.toString(); + } + + public boolean isEmpty() { + boolean result=true; + for(StructuralComponent branch:subComponents){ + if(!branch.isEmpty()){ + result=false; + break; + } + } + return result; + } + + /*@Override + public void buildEvaluationMap(Map, Double> evaluationMap, Double currentValue) { + List services=new LinkedList(); + for(StructuralComponent component:subComponents) + { + if(component instanceof AbstractWebService) + { + services.add((AbstractWebService)component); + }else + ((CompositeStructuralComponent)component).buildEvaluationMap(evaluationMap,currentValue*averageNumberOfIterations); + } + if(services.size()>0) + evaluationMap.put(services, currentValue*averageNumberOfIterations); + }*/ + @Override + public String toString() + { + return toStructuralString(""); + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/Sequence.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/Sequence.java new file mode 100644 index 0000000..25d4636 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/Sequence.java @@ -0,0 +1,92 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding; + +import java.util.LinkedList; +import java.util.List; + +/** + * + * @author japarejo + */ +public class Sequence implements CompositeStructuralComponent { + protected List subComponents; + public Sequence() + { + subComponents=new LinkedList(); + } + + + public List getSubComponents() { + return subComponents; + } + /* + @Override + public void buildEvaluationMap(Map, Double> evaluationMap, Double currentValue) { + List services=new LinkedList(); + for(StructuralComponent component:subComponents) + { + if(component instanceof AbstractWebService) + { + services.add((AbstractWebService)component); + }else + ((CompositeStructuralComponent)component).buildEvaluationMap(evaluationMap,currentValue); + } + if(services.size()>0) + evaluationMap.put(services, currentValue); + }*/ + + + public Double getPonderation(StructuralComponent subcomponent) { + return 1.0; + } + + @Override + public String toString() + { + StringBuffer buffer=new StringBuffer("Sec["); + for(StructuralComponent subComponent:subComponents) + buffer.append(subComponent.toString()+","); + buffer.append("]"); + return buffer.toString(); + } + + + public String toStructuralString(String prefix) { + StringBuffer buffer=new StringBuffer(prefix+"SEC["); + String newline = System.getProperty("line.separator"); + String myprefix=prefix+" "; + if(subComponents.size()>0) + { + if(!(subComponents.get(0) instanceof AbstractWebService)) + buffer.append(newline); + } + boolean newlinegenerated=false; + for(StructuralComponent subComponent:subComponents) + if(subComponent instanceof CompositeStructuralComponent){ + buffer.append(newline+subComponent.toStructuralString(myprefix)+newline+prefix+","); + newlinegenerated=true; + }else + buffer.append(subComponent.toStructuralString("")+","); + buffer.append(newline+prefix+"]"); + return buffer.toString(); + } + + + public boolean isEmpty() { + boolean result=true; + for(StructuralComponent branch:subComponents){ + if(!branch.isEmpty()){ + result=false; + break; + } + } + return result; + } + + + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/StructuralComponent.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/StructuralComponent.java new file mode 100644 index 0000000..8a66d54 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/StructuralComponent.java @@ -0,0 +1,17 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding; + +import java.io.Serializable; + +/** + * + * @author japarejo + */ +public interface StructuralComponent extends Serializable { + public String toStructuralString(String prefix); + public boolean isEmpty(); +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/WSCompositionStructure.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/WSCompositionStructure.java new file mode 100644 index 0000000..f0877c4 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/WSCompositionStructure.java @@ -0,0 +1,238 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * + * @author japarejo + */ +public class WSCompositionStructure implements Serializable{ + protected Set components; + protected StructuralComponent structure; + protected double numberOfexecutedTasks; + + public WSCompositionStructure(StructuralComponent structure) + { + this.structure=structure; + components=new HashSet(); + createComponents(); + numberOfexecutedTasks=numberOfExecutedTasks(structure); + } + + public Set getComponents() { + return components; + } + + public StructuralComponent getStructure() { + return structure; + } + + public int maxNestingLevel() { + return computeMaxNestingLevel(structure); + } + + private int NBuildingBlocks(Class aClass, StructuralComponent structure) { + int result=0; + if(structure instanceof CompositeStructuralComponent) + { + CompositeStructuralComponent compositeComponent=(CompositeStructuralComponent)structure; + for(StructuralComponent subComponent:compositeComponent.getSubComponents()) + { + result+=NBuildingBlocks(aClass, subComponent); + } + if(structure.getClass().equals(aClass)) + result++; + } + return result; + } + + private void addComponent(StructuralComponent structure) { + if(structure instanceof AbstractWebService) + components.add((AbstractWebService) structure); + else if (structure instanceof EmptyComponent) { + // Do nothing, no AbstractWebService here + } else if (structure instanceof CompositeStructuralComponent) { + Collection subcomponents=((CompositeStructuralComponent)structure).getSubComponents(); + for(StructuralComponent subcomponent:subcomponents) + addComponent(subcomponent); + } + } + + private int computeMaxNestingLevel(StructuralComponent structure) { + int result=0; + int auxNestingLevel; + if(structure instanceof CompositeStructuralComponent) + { + result=1; + CompositeStructuralComponent compositeComponent=(CompositeStructuralComponent)structure; + for(StructuralComponent subComponent:compositeComponent.getSubComponents()) + { + if(subComponent instanceof Sequence) + auxNestingLevel=computeMaxNestingLevel(subComponent); + else + auxNestingLevel=1+computeMaxNestingLevel(subComponent); + if(auxNestingLevel>result) + result=auxNestingLevel; + } + } + return result; + } + + private void createComponents() { + addComponent(structure); + } + + public int computeCyclomaticComplexity() + { + return computeCyclomaticComplexity(structure)+1; + } + + public int computeMaxNesting() + { + return computeMaxNestingLevel(structure); + } + + public int numberOfActivities() + { + return numberOfActivities(structure); + } + + private int computeCyclomaticComplexity(StructuralComponent component) + { + int result=0; + if(component instanceof CompositeStructuralComponent) + { + CompositeStructuralComponent compositeComponent=(CompositeStructuralComponent)component; + if(compositeComponent instanceof Loop){ + result=1; + for(StructuralComponent subComponent:compositeComponent.getSubComponents()) + { + result+=computeCyclomaticComplexity(subComponent); + } + }else if(compositeComponent instanceof Branch){ + result=compositeComponent.getSubComponents().size()-1; + for(StructuralComponent subComponent:compositeComponent.getSubComponents()) + { + result+=computeCyclomaticComplexity(subComponent); + } + }else if(compositeComponent instanceof Flow){ + result=compositeComponent.getSubComponents().size()-1; + for(StructuralComponent subComponent:compositeComponent.getSubComponents()) + { + result+=computeCyclomaticComplexity(subComponent); + } + }else if(component instanceof Sequence){ + for(StructuralComponent subComponent:compositeComponent.getSubComponents()) + { + result+=computeCyclomaticComplexity(subComponent); + } + } + } + return result; + } + + private int numberOfActivities(StructuralComponent structure) { + int result=1; + if(structure instanceof CompositeStructuralComponent) + { + CompositeStructuralComponent compositeComponent=(CompositeStructuralComponent)structure; + for(StructuralComponent subComponent:compositeComponent.getSubComponents()) + { + result+=numberOfActivities(subComponent); + } + if(structure instanceof Sequence) + result=result-1; + if(structure instanceof Flow) + result=result-1; + } + return result; + } + + private double numberOfExecutedTasks(StructuralComponent structure) { + double result=0; + if(structure instanceof CompositeStructuralComponent) + { + CompositeStructuralComponent compositeComponent=(CompositeStructuralComponent)structure; + for(StructuralComponent subComponent:compositeComponent.getSubComponents()) + { + if(subComponent instanceof AbstractWebService) + result+=compositeComponent.getPonderation(subComponent); + else + result+=numberOfExecutedTasks(subComponent)*compositeComponent.getPonderation(subComponent); + } + } else if (structure instanceof EmptyComponent) { + result = 0; + }else + result=1; + return result; + } + + private int numberOfTaskActivities(StructuralComponent structure) + { + int result=0; + if(structure instanceof CompositeStructuralComponent) + { + CompositeStructuralComponent compositeComponent=(CompositeStructuralComponent)structure; + for(StructuralComponent subComponent:compositeComponent.getSubComponents()) + { + if(subComponent instanceof CompositeStructuralComponent) + result+=numberOfTaskActivities(subComponent); + else + result++; + } + }else{ + result=1; + } + return result; + } + + public double perecentageOfControlFlowActivities() + { + double percentageOfTaskActivities=((double)(numberOfTaskActivities(structure)))/((double)(numberOfActivities(structure))); + return 1.0 - percentageOfTaskActivities; + } + + public double numberOfExecutedTasks() + { + if(numberOfexecutedTasks==Double.MIN_VALUE) + numberOfexecutedTasks=numberOfExecutedTasks(structure); + return numberOfexecutedTasks; + } + + public double percentageOfLoops() + { + double result=0; + double nloops=(double)NBuildingBlocks(Loop.class, structure); + result=nloops/((double)(numberOfActivities(structure)-numberOfTaskActivities(structure))); + return result; + } + public double averageIterationsPerLoop() + { + double nloops=(double)NBuildingBlocks(Loop.class, structure); + double nTotalIterations=(double)NtotalIterations(structure); + return nTotalIterations/nloops; + } + public double NtotalIterations(StructuralComponent structure) + { + double result=0; + if(structure instanceof CompositeStructuralComponent) + { + CompositeStructuralComponent compositeComponent=(CompositeStructuralComponent)structure; + for(StructuralComponent subComponent:compositeComponent.getSubComponents()) + { + result+=NtotalIterations(subComponent); + } + if(structure instanceof Loop) + result+=((Loop)structure).getAverageNumberOfIterations(); + } + return result; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/Controller.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/Controller.java new file mode 100644 index 0000000..adaf380 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/Controller.java @@ -0,0 +1,136 @@ +package es.us.isa.qosawarewsbinding.api; + +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.api.dto.SolveRequest; +import es.us.isa.qosawarewsbinding.api.dto.SolveResponse; +import es.us.isa.qosawarewsbinding.api.mapping.ProblemBuildResult; +import es.us.isa.qosawarewsbinding.api.mapping.ProblemBuilder; +import es.us.isa.qosawarewsbinding.api.solver.ManyHeuristicSolver; +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Controller implements HttpHandler { + private final Gson gson = new Gson(); + + @Override + public void handle(HttpExchange exchange) throws IOException { + if (!"POST".equalsIgnoreCase(exchange.getRequestMethod())) { + exchange.sendResponseHeaders(405, -1); + return; + } + + try { + SolveRequest req = gson.fromJson(new InputStreamReader(exchange.getRequestBody()), SolveRequest.class); + SolveResponse resp = process(req); + + String jsonResp = gson.toJson(resp); + exchange.getResponseHeaders().set("Content-Type", "application/json"); + exchange.sendResponseHeaders(200, jsonResp.length()); + OutputStream os = exchange.getResponseBody(); + os.write(jsonResp.getBytes()); + os.close(); + } catch (IllegalArgumentException e) { + String error = "{\"error\": \"" + e.getMessage() + "\"}"; + exchange.sendResponseHeaders(422, error.length()); + OutputStream os = exchange.getResponseBody(); + os.write(error.getBytes()); + os.close(); + } catch (Exception e) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + String stackTrace = sw.toString().replace("\"", "'").replace("\n", "\\n"); + + String error = "{\"error\": \"" + e.getMessage() + "\", \"stack\": \"" + stackTrace + "\"}"; + exchange.sendResponseHeaders(500, error.length()); + OutputStream os = exchange.getResponseBody(); + os.write(error.getBytes()); + os.close(); + } + } + + private SolveResponse process(SolveRequest req) { + ProblemBuilder builder = new ProblemBuilder(); + ProblemBuildResult mapped = builder.build(req); + QoSAwareWSCompositionProblem problem = mapped.problem; + + int iterations = 1000; + int archiveSize = 20; + // int populationSize = 100; // Passed but not used in current simple + // implementation + + if (req.config != null) { + if (req.config.max_iterations > 0) + iterations = req.config.max_iterations; + if (req.config.archive_size > 0) + archiveSize = req.config.archive_size; + } + + long start = System.currentTimeMillis(); + ManyHeuristicSolver solver = new ManyHeuristicSolver(); + // Passing population size to solver if we decide to use it in future + List paretoFront = solver.solve(problem, iterations, archiveSize); + long end = System.currentTimeMillis(); + + if (paretoFront.isEmpty()) { + throw new IllegalArgumentException( + "No feasible solution found after " + iterations + " iterations."); + } + + SolveResponse resp = new SolveResponse(); + resp.execution_time = end - start; + resp.iterations_count = iterations; + resp.status = "optimized"; + resp.solutions = new ArrayList<>(); + + for (QoSAwareWSCompositionSolution sol : paretoFront) { + SolveResponse.SolutionDTO dto = new SolveResponse.SolutionDTO(); + dto.is_feasible = problem.feasibilityDistance(sol) <= 0; + dto.selection = new HashMap<>(); + dto.aggregated_features = new HashMap<>(); + + // Calculate objective value? For Many-Obj, it's a vector not a single value. + // keeping objective_value null or 0.0 effectively. + dto.objective_value = 0.0; + + for (QoSProperty p : mapped.propertyMap.values()) { + double val = mapped.qosModel.evaluate(sol, p, mapped.structure); + dto.aggregated_features.put(p.getName(), val); + } + + for (Map.Entry entry : mapped.taskMap.entrySet()) { + String taskId = entry.getKey(); + AbstractWebService aws = entry.getValue(); + ConcreteWebService cws = sol.getSelectedService(aws); + if (cws != null) { + dto.selection.put(taskId, cws.getName()); + } + } + resp.solutions.add(dto); + } + + // Fill top-level selection with the first solution for backward compatibility + // (optional but good practice) + if (!resp.solutions.isEmpty()) { + resp.selection = resp.solutions.get(0).selection; + resp.aggregated_features = resp.solutions.get(0).aggregated_features; + } + + return resp; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/Server.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/Server.java new file mode 100644 index 0000000..336cbfd --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/Server.java @@ -0,0 +1,28 @@ +package es.us.isa.qosawarewsbinding.api; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.concurrent.Executors; + +public class Server { + public static void main(String[] args) throws IOException { + int port = 8080; + HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); + server.createContext("/health", new HttpHandler() { + @Override + public void handle(HttpExchange exchange) throws IOException { + byte[] body = "{\"status\":\"ok\"}".getBytes("UTF-8"); + exchange.getResponseHeaders().add("Content-Type", "application/json"); + exchange.sendResponseHeaders(200, body.length); + exchange.getResponseBody().write(body); + exchange.close(); + } + }); + server.createContext("/solve", new Controller()); + server.setExecutor(Executors.newCachedThreadPool()); + server.start(); + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/dto/SolveRequest.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/dto/SolveRequest.java new file mode 100644 index 0000000..bda67b4 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/dto/SolveRequest.java @@ -0,0 +1,83 @@ +package es.us.isa.qosawarewsbinding.api.dto; + +import java.util.List; +import java.util.Map; + +public class SolveRequest { + public String id; + public CompositionStructure composition; + public Map market; + public QoSModel features; + public SolvingConfig config; + public List constraints; + + public static class CompositionStructure { + public String type; // "structured" + public Node root; + } + + public static class Node { + public String id; + public String kind; // TASK, SEQ, AND, XOR, LOOP + public String task_id; // if TASK + public List children; // if SEQ, AND + public List branches; // if XOR + public Node body; // if LOOP + public Double expected_iterations; // if LOOP + } + + public static class Branch { + public double p; + public Node child; + } + + public static class ServiceCandidates { + public List services; + } + + public static class Service { + public String id; // service concrete ID (e.g. "s11") + public String name; + public String provider_id; // provider identity for DEPENDENCY constraints + public Map features; + } + + public static class QoSModel { + public Map properties; + public Map weights; + public Map aggregation; + } + + public static class QoSPropertyDef { + public String direction; // "minimize", "maximize" + public Double min; + public Double max; + } + + public static class AggregationPolicy { + // Simple map from operator (seq, flow, etc.) to function name (sum, max, etc.) + public String seq; + public String flow; // "and" in request mapped to "flow" in engine + public String branch; // "xor" + public String loop; + } + + public static class SolvingConfig { + public int max_iterations; + public int archive_size; + } + + public static class Constraint { + public String id; + public String kind; // "attribute_bound", "range_global", "dependency", "local_attribute_bound" + public String scope; // "global", "local" + public String attribute_id; + public String op; // <=, <, >=, >, ==, !=, IN_RANGE + public Double value; + public Double min; // For IN_RANGE + public Double max; // For IN_RANGE + public java.util.List tasks; // For LOCAL and DEPENDENCY + public String type; // For DEPENDENCY (SAME_PROVIDER, DIFFERENT_PROVIDER) + public Boolean hard; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/dto/SolveResponse.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/dto/SolveResponse.java new file mode 100644 index 0000000..8dccd7f --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/dto/SolveResponse.java @@ -0,0 +1,23 @@ +package es.us.isa.qosawarewsbinding.api.dto; + +import java.util.Map; +import java.util.List; + +public class SolveResponse { + public String status; // optimized, error + public Map selection; // task_id -> service_id + public Map aggregated_features; // aggregated qos + public Object metadata; + public String error; + public Long execution_time; + public Integer iterations_count; + + public List solutions; + + public static class SolutionDTO { + public Map selection; + public Map aggregated_features; + public boolean is_feasible; + public Double objective_value; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/mapping/ProblemBuildResult.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/mapping/ProblemBuildResult.java new file mode 100644 index 0000000..9e9ffd8 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/mapping/ProblemBuildResult.java @@ -0,0 +1,36 @@ +package es.us.isa.qosawarewsbinding.api.mapping; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.WSCompositionStructure; +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.problem.WSCompositionQoSModel; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; + +import java.util.Map; +import java.util.Set; + +public class ProblemBuildResult { + public final QoSAwareWSCompositionProblem problem; + public final WSCompositionStructure structure; + public final WSCompositionQoSModel qosModel; + public final Map taskMap; + public final Map> propertyMap; + public final Map> market; + + public ProblemBuildResult( + QoSAwareWSCompositionProblem problem, + WSCompositionStructure structure, + WSCompositionQoSModel qosModel, + Map taskMap, + Map> propertyMap, + Map> market + ) { + this.problem = problem; + this.structure = structure; + this.qosModel = qosModel; + this.taskMap = taskMap; + this.propertyMap = propertyMap; + this.market = market; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/mapping/ProblemBuilder.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/mapping/ProblemBuilder.java new file mode 100644 index 0000000..37f90f6 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/mapping/ProblemBuilder.java @@ -0,0 +1,296 @@ +package es.us.isa.qosawarewsbinding.api.mapping; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.Branch; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.EmptyComponent; +import es.us.isa.qosawarewsbinding.Flow; +import es.us.isa.qosawarewsbinding.Loop; +import es.us.isa.qosawarewsbinding.Sequence; +import es.us.isa.qosawarewsbinding.StructuralComponent; +import es.us.isa.qosawarewsbinding.WSCompositionStructure; +import es.us.isa.qosawarewsbinding.api.dto.SolveRequest; +import es.us.isa.qosawarewsbinding.problem.BinaryOperator; +import es.us.isa.qosawarewsbinding.problem.GlobalQoSWSCompositionConstraint; +import es.us.isa.qosawarewsbinding.problem.LocalQoSWSCompositionConstraint; +import es.us.isa.qosawarewsbinding.problem.ProviderRelationWSCompositionConstraint; +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.problem.RangeGlobalQoSWSCompositionConstraint; +import es.us.isa.qosawarewsbinding.problem.SimpleUnfeasibilityPenalizator; +import es.us.isa.qosawarewsbinding.problem.WSCompositionQoSModel; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.qos.QoSPropertyType; +import es.us.isa.qosawarewsbinding.qos.aggretation.AggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.MaxAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.MinAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.ScaledSumAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryAggregationFunction; +import es.us.isa.qosawarewsbinding.util.BoundedDomain; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class ProblemBuilder { + public ProblemBuildResult build(SolveRequest req) { + Map taskMap = new HashMap(); + Map serviceProviderMap = new HashMap(); + + StructuralComponent root = mapNode(req.composition.root, taskMap); + WSCompositionStructure structure = new WSCompositionStructure(root); + + Map> propertyMap = new HashMap>(); + Set qosProperties = new HashSet(); + + for (Map.Entry entry : req.features.properties.entrySet()) { + QoSPropertyType type = "maximize".equals(entry.getValue().direction) + ? QoSPropertyType.POSITIVE + : QoSPropertyType.NEGATIVE; + + Double min = entry.getValue().min != null ? entry.getValue().min : 0.0; + Double max = entry.getValue().max != null ? entry.getValue().max : 1.0; + + QoSProperty prop = new QoSProperty( + entry.getKey(), + new BoundedDomain(min, max), + type + ); + qosProperties.add(prop); + propertyMap.put(entry.getKey(), prop); + } + WSCompositionQoSModel qosModel = new WSCompositionQoSModel(qosProperties); + + Map weights = new HashMap(); + for (Map.Entry entry : req.features.weights.entrySet()) { + QoSProperty prop = propertyMap.get(entry.getKey()); + if (prop != null) { + weights.put(prop, entry.getValue()); + } + } + qosModel.setQosPropertiesWeights(weights); + + for (Map.Entry entry : req.features.aggregation.entrySet()) { + QoSProperty prop = propertyMap.get(entry.getKey()); + SolveRequest.AggregationPolicy policy = entry.getValue(); + + qosModel.setAggregationFunction(prop, Sequence.class, getAggFunc(policy.seq)); + qosModel.setAggregationFunction(prop, Flow.class, getAggFunc(policy.flow)); + qosModel.setAggregationFunction(prop, Branch.class, getAggFunc(policy.branch)); + qosModel.setAggregationFunction(prop, Loop.class, getAggFunc(policy.loop)); + } + + Map> market = new HashMap>(); + for (Map.Entry entry : taskMap.entrySet()) { + String taskId = entry.getKey(); + AbstractWebService aws = entry.getValue(); + Set candidates = new HashSet(); + + SolveRequest.ServiceCandidates sc = req.market.get(taskId); + if (sc != null && sc.services != null) { + for (SolveRequest.Service s : sc.services) { + ConcreteWebService cws = new ConcreteWebService(s.id, aws); + + if (s.provider_id != null) { + serviceProviderMap.put(s.id, s.provider_id); + } + + for (QoSProperty p : propertyMap.values()) { + Double val = s.features.get(p.getName()); + if (val == null) { + if (p.getType() == QoSPropertyType.POSITIVE) { + val = 0.0; + } else { + val = 999999.0; + } + } + cws.setQoSValue(p, val); + } + candidates.add(cws); + } + } + market.put(aws, candidates); + } + + QoSAwareWSCompositionProblem problem = new QoSAwareWSCompositionProblem( + structure, + market, + qosModel, + new LinkedList() + ); + problem.setPenalizator(new SimpleUnfeasibilityPenalizator()); + + applyConstraints(req, problem, taskMap, propertyMap, serviceProviderMap); + + return new ProblemBuildResult(problem, structure, qosModel, taskMap, propertyMap, market); + } + + private void applyConstraints( + SolveRequest req, + QoSAwareWSCompositionProblem problem, + Map taskMap, + Map> propertyMap, + Map serviceProviderMap + ) { + if (req.constraints == null) { + return; + } + + for (SolveRequest.Constraint c : req.constraints) { + boolean hard = c.hard != null ? c.hard : true; + + if ("dependency".equalsIgnoreCase(c.kind)) { + List relatedTasks = new ArrayList(); + if (c.tasks != null) { + for (String tid : c.tasks) { + AbstractWebService t = taskMap.get(tid); + if (t != null) { + relatedTasks.add(t); + } + } + } + ProviderRelationWSCompositionConstraint.Type type = + "SAME_PROVIDER".equalsIgnoreCase(c.type) + ? ProviderRelationWSCompositionConstraint.Type.SAME_PROVIDER + : ProviderRelationWSCompositionConstraint.Type.DIFFERENT_PROVIDER; + + ProviderRelationWSCompositionConstraint depConstraint = new ProviderRelationWSCompositionConstraint( + problem, type, relatedTasks, hard); + depConstraint.setServiceProviderMap(serviceProviderMap); + problem.getConstraints().add(depConstraint); + continue; + } + + if ("attribute_bound".equalsIgnoreCase(c.kind)) { + QoSProperty prop = propertyMap.get(c.attribute_id); + if (prop == null) { + continue; + } + + BinaryOperator op = getOperator(c.op); + + if (BinaryOperator.IN_RANGE.equals(op)) { + problem.getConstraints() + .add(new RangeGlobalQoSWSCompositionConstraint(problem, prop, c.min, c.max, hard)); + continue; + } + + if ("local".equalsIgnoreCase(c.scope)) { + if (c.tasks != null) { + for (String tid : c.tasks) { + AbstractWebService t = taskMap.get(tid); + if (t != null) { + problem.getConstraints().add( + new LocalQoSWSCompositionConstraint(problem, prop, op, c.value, t, hard)); + } + } + } + } else { + GlobalQoSWSCompositionConstraint gc = new GlobalQoSWSCompositionConstraint(problem, prop, + c.value, op); + gc.setHard(hard); + problem.getConstraints().add(gc); + } + } + } + } + + private AggregationFunction getAggFunc(String name) { + if ("sum".equalsIgnoreCase(name)) + return SumatoryAggregationFunction.getInstance(); + if ("product".equalsIgnoreCase(name)) + return ProductoryAggregationFunction.getInstance(); + if ("max".equalsIgnoreCase(name)) + return MaxAggregationFunction.getInstance(); + if ("min".equalsIgnoreCase(name)) + return MinAggregationFunction.getInstance(); + if ("scaled_sum".equalsIgnoreCase(name)) + return ScaledSumAggregationFunction.getInstance(); + return SumatoryAggregationFunction.getInstance(); + } + + private StructuralComponent mapNode(SolveRequest.Node node, Map taskMap) { + if (node == null) { + return null; + } + if ("TASK".equals(node.kind)) { + AbstractWebService aws = new AbstractWebService(node.task_id); + taskMap.put(node.task_id, aws); + return aws; + } else if ("SEQ".equals(node.kind)) { + Sequence seq = new Sequence(); + if (node.children != null) { + for (SolveRequest.Node child : node.children) { + StructuralComponent sc = mapNode(child, taskMap); + if (sc != null) { + seq.getSubComponents().add(sc); + } + } + } + return seq; + } else if ("AND".equals(node.kind)) { + Flow flow = new Flow(); + if (node.children != null) { + for (SolveRequest.Node child : node.children) { + StructuralComponent sc = mapNode(child, taskMap); + if (sc != null) { + flow.getSubComponents().add(sc); + } + } + } + return flow; + } else if ("XOR".equals(node.kind)) { + Branch branch = new Branch(); + if (node.branches != null) { + for (SolveRequest.Branch b : node.branches) { + StructuralComponent child = mapNode(b.child, taskMap); + if (child != null) { + branch.addBranch(child, b.p); + } + } + } + return branch; + } else if ("LOOP".equals(node.kind)) { + int iterations = 1; + if (node.expected_iterations != null) { + iterations = (int) Math.round(node.expected_iterations.doubleValue()); + if (iterations < 0) { + iterations = 0; + } + } + Loop loop = new Loop(iterations); + if (node.body != null) { + StructuralComponent body = mapNode(node.body, taskMap); + if (body != null) { + loop.getSubComponents().add(body); + } + } + return loop; + } else if ("ELEMENT".equals(node.kind)) { + return new EmptyComponent(node.id); + } + return null; + } + + private BinaryOperator getOperator(String op) { + if ("==".equals(op)) + return BinaryOperator.EQUAL; + if ("!=".equals(op)) + return BinaryOperator.DISTINCT; + if (">".equals(op)) + return BinaryOperator.GREATER; + if (">=".equals(op)) + return BinaryOperator.GREATEREQUAL; + if ("<".equals(op)) + return BinaryOperator.LOWER; + if ("<=".equals(op)) + return BinaryOperator.LOWEREQUAL; + if ("IN_RANGE".equals(op) || "in_range".equalsIgnoreCase(op)) + return BinaryOperator.IN_RANGE; + return BinaryOperator.EQUAL; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/solver/ManyHeuristicSolver.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/solver/ManyHeuristicSolver.java new file mode 100644 index 0000000..8296ee6 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/api/solver/ManyHeuristicSolver.java @@ -0,0 +1,127 @@ +package es.us.isa.qosawarewsbinding.api.solver; + +import es.us.isa.qosawarewsbinding.api.dto.SolveResponse; +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; +import es.us.isa.qosawarewsbinding.solution.vector.QoSAwareWSCompositionVectorSolution; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.qos.QoSPropertyType; + +import java.util.ArrayList; +import java.util.List; +import java.util.Iterator; +import java.util.Random; + +public class ManyHeuristicSolver { + + public List solve(QoSAwareWSCompositionProblem problem, int iterations, + int archiveSize) { + List archive = new ArrayList<>(); + + for (int i = 0; i < iterations; i++) { + QoSAwareWSCompositionSolution sol = (QoSAwareWSCompositionSolution) new QoSAwareWSCompositionVectorSolution( + problem).createRandom(); + + // Should verify feasibility? + // Existing logic: problem.feasibilityDistance(sol) <= 0 + if (problem.feasibilityDistance(sol) <= 0) { + updateArchive(archive, sol, problem, archiveSize); + } + } + return archive; + } + + private void updateArchive(List archive, QoSAwareWSCompositionSolution candidate, + QoSAwareWSCompositionProblem problem, int maxSize) { + boolean dominated = false; + Iterator it = archive.iterator(); + + while (it.hasNext()) { + QoSAwareWSCompositionSolution existing = it.next(); + int dom = compareDominance(candidate, existing, problem); + + if (dom == -1) { // Candidate is dominated by an existing solution + dominated = true; + break; + } else if (dom == 1) { // Candidate dominates existing + it.remove(); + } else { + // Check if they are identical (duplicate objective values) + if (isIdentical(candidate, existing, problem)) { + dominated = true; // Treat as dominated to avoid adding duplicate + break; + } + } + } + + if (!dominated) { + archive.add(candidate); + // Pruning mechanism if archive is full + // For now, if we exceed size, remove random or oldest to keep it simple as MVP + if (archive.size() > maxSize) { + archive.remove(0); + } + } + } + + private boolean isIdentical(QoSAwareWSCompositionSolution a, QoSAwareWSCompositionSolution b, + QoSAwareWSCompositionProblem problem) { + for (QoSProperty p : problem.getQosmodel().getQosProperties()) { + Double va = problem.getQosmodel().evaluate(a, p, problem.getStructure()); + Double vb = problem.getQosmodel().evaluate(b, p, problem.getStructure()); + + if (va == null || vb == null) + continue; + + // Check for equality with small tolerance for floating point arithmetic + if (Math.abs(va - vb) > 0.000001) { + return false; + } + } + return true; + } + + // 1: a dominates b + // -1: b dominates a + // 0: non-dominated + private int compareDominance(QoSAwareWSCompositionSolution a, QoSAwareWSCompositionSolution b, + QoSAwareWSCompositionProblem problem) { + boolean betterInAny = false; + boolean worseInAny = false; + + for (QoSProperty p : problem.getQosmodel().getQosProperties()) { + // We need double values + Double va = problem.getQosmodel().evaluate(a, p, problem.getStructure()); + Double vb = problem.getQosmodel().evaluate(b, p, problem.getStructure()); + + if (va == null || vb == null) + continue; + + boolean aBetter = false; + boolean aWorse = false; + + if (p.getType() == QoSPropertyType.POSITIVE) { + if (va > vb) + aBetter = true; + if (va < vb) + aWorse = true; + } else { + if (va < vb) + aBetter = true; + if (va > vb) + aWorse = true; + } + + if (aBetter) + betterInAny = true; + if (aWorse) + worseInAny = true; + } + + if (betterInAny && !worseInAny) + return 1; + if (worseInAny && !betterInAny) + return -1; + return 0; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/BinaryOperator.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/BinaryOperator.java new file mode 100644 index 0000000..59d0536 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/BinaryOperator.java @@ -0,0 +1,14 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem; + +/** + * + * @author japarejo + */ +public enum BinaryOperator { + EQUAL, DISTINCT(), GREATER, GREATEREQUAL, LOWER, LOWEREQUAL, IN_RANGE +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/Constraint.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/Constraint.java new file mode 100644 index 0000000..d228d9c --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/Constraint.java @@ -0,0 +1,8 @@ +package es.us.isa.qosawarewsbinding.problem; + +public interface Constraint { + public boolean meets (X solution); + public double meetingDistance (X solution); + +} + diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/EvaluationCountProblem.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/EvaluationCountProblem.java new file mode 100644 index 0000000..d7aa8b9 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/EvaluationCountProblem.java @@ -0,0 +1,38 @@ +package es.us.isa.qosawarewsbinding.problem; + +import es.us.isa.qosawarewsbinding.solution.Solution; + +public abstract class EvaluationCountProblem implements Problem { + private long fitnessEvaluationCount; + private long feasibilityEvaluationCount; + + public EvaluationCountProblem() + { + fitnessEvaluationCount=0; + feasibilityEvaluationCount=0; + } + + + public final double fitness(Solution sol) { + fitnessEvaluationCount++; + return computeFitness(sol); + } + + public final boolean feasible(Solution sol) { + feasibilityEvaluationCount++; + return computeFeasibility(sol); + } + + protected abstract boolean computeFeasibility(Solution sol); + + protected abstract double computeFitness(Solution sol); + + public long getFitnessEvaluationCount() { + return fitnessEvaluationCount; + } + + public long getFeasibilityEvaluationCount() { + return feasibilityEvaluationCount; + } + +} \ No newline at end of file diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ExecutionPath.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ExecutionPath.java new file mode 100644 index 0000000..194596b --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ExecutionPath.java @@ -0,0 +1,76 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import es.us.isa.qosawarewsbinding.AbstractWebService; + +/** + * + * @author japarejo + */ +public class ExecutionPath { + private QoSAwareWSCompositionProblem problem; + private List executedTasks; + private double probabilityOfExecution; + + public ExecutionPath(QoSAwareWSCompositionProblem problem, List execTasks,double prob) + { + this.problem=problem; + this.executedTasks=new ArrayList(execTasks.size()); + this.executedTasks.addAll(execTasks); + this.probabilityOfExecution=prob; + } + + public ExecutionPath(QoSAwareWSCompositionProblem problem, double prob) + { + this.problem=problem; + this.executedTasks=new LinkedList(); + this.probabilityOfExecution=prob; + } + + public QoSAwareWSCompositionProblem getProblem() { + return problem; + } + + public List getExecutedTasks() { + return executedTasks; + } + + public double getProbabilityOfExecution() { + return probabilityOfExecution; + } + + public void setProbabilityOfExecution(double pk) { + this.probabilityOfExecution = pk; + } + + @Override + public boolean equals(Object obj) + { + boolean result=false; + if(obj instanceof ExecutionPath) + { + ExecutionPath myobj=(ExecutionPath)obj; + result=(problem==myobj.getProblem()); + result=result && (probabilityOfExecution==myobj.getProbabilityOfExecution()); + result=(result && executedTasks.equals(myobj.getExecutedTasks())); + } + return result; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 29 * hash + (this.problem != null ? this.problem.hashCode() : 0); + hash = 29 * hash + (this.executedTasks != null ? this.executedTasks.hashCode() : 0); + hash = 29 * hash + (int) (Double.doubleToLongBits(this.probabilityOfExecution) ^ (Double.doubleToLongBits(this.probabilityOfExecution) >>> 32)); + return hash; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ExecutionPathsBuilder.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ExecutionPathsBuilder.java new file mode 100644 index 0000000..444f2d4 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ExecutionPathsBuilder.java @@ -0,0 +1,16 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem; + +import java.util.Set; + +/** + * + * @author japarejo + */ +public interface ExecutionPathsBuilder{ + public Set buildPaths(QoSAwareWSCompositionProblem aThis); +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/FeasibilityAwareProblem.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/FeasibilityAwareProblem.java new file mode 100644 index 0000000..28ff538 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/FeasibilityAwareProblem.java @@ -0,0 +1,49 @@ +package es.us.isa.qosawarewsbinding.problem; + +import es.us.isa.qosawarewsbinding.solution.Solution; + +public abstract class FeasibilityAwareProblem extends EvaluationCountProblem { + + private UnfeasibilityPenalizator penalizator; + + public FeasibilityAwareProblem() + { + penalizator=null; + } + + public FeasibilityAwareProblem(UnfeasibilityPenalizator penalizator) + { + this.penalizator=penalizator; + } + + + @Override + protected double computeFitness(Solution sol) { + double result=feasibilityFreeFitness(sol); + if(penalizator!=null) + result=getPenalizator().penalize(result,feasibilityDistance(sol)); + return result; + } + + public abstract double feasibilityDistance(Solution sol); + + public abstract double feasibilityFreeFitness(Solution sol); + + @Override + protected boolean computeFeasibility(Solution sol) { + return feasibilityDistance(sol) <= 0; + } + + /** + * @return the penalizator + */ + public UnfeasibilityPenalizator getPenalizator() { + return penalizator; + } + + public void setPenalizator(UnfeasibilityPenalizator penalizator) { + this.penalizator = penalizator; + } + +} + diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/GlobalQoSWSCompositionConstraint.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/GlobalQoSWSCompositionConstraint.java new file mode 100644 index 0000000..def3607 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/GlobalQoSWSCompositionConstraint.java @@ -0,0 +1,113 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem; + +import java.io.Serializable; + +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; + +/** + * + * @author japarejo + */ +public class GlobalQoSWSCompositionConstraint extends WSCompositionConstraint implements Serializable { + private QoSProperty property; + private BinaryOperator operator; + private Double value; + + public GlobalQoSWSCompositionConstraint(QoSAwareWSCompositionProblem problem, QoSProperty property, Double value, BinaryOperator operator) + { + super(problem); + if(problem!=null){ + if(problem.getQosmodel().getQosProperties().contains(property)) + { + this.property=property; + this.operator=operator; + this.value=value; + }else + throw new IllegalArgumentException("Property must be part of the QoS model of the problem at hand."); + }else{ + this.property=property; + this.operator=operator; + this.value=value; + } + } + + @Override + public boolean meets(QoSAwareWSCompositionSolution solution) { + return meetingDistance(solution)==0; + } + + @Override + public double meetingDistance(QoSAwareWSCompositionSolution solution) { + Double currentValue=problem.getQosmodel().evaluate(solution,getProperty(),problem.getStructure()); + return meetingDistance(currentValue); + } + + private double meetingDistance(Double currentValue) { + double result=getValue().doubleValue()-currentValue.doubleValue(); + if(getOperator()==BinaryOperator.EQUAL){ + result=Math.abs(result); + }else if(getOperator()==BinaryOperator.DISTINCT){ + if(result==0) + result=1; + else + result=0; + }else if(getOperator()==BinaryOperator.GREATER){ + if(result<0) + result=0; + else if(result==0) + result=Double.MIN_VALUE; + }else if(getOperator()==BinaryOperator.GREATEREQUAL){ + if(result<0) + result=0; + }else if(getOperator()==BinaryOperator.LOWER){ + if(result>0) + result=0; + else if(result<0) + result=Math.abs(result); + else + result=Double.MIN_VALUE; + }else if(getOperator()==BinaryOperator.LOWEREQUAL){ + if(result>0) + result=0; + else if(result<0) + result=Math.abs(result); + } + return result; + } + + public String toString() + { + String result=getOperator()+"("+getProperty().getName()+","+getValue()+")"; + return result; + } + + public QoSProperty getProperty() { + return property; + } + + public void setProperty(QoSProperty property) { + this.property = property; + } + + public BinaryOperator getOperator() { + return operator; + } + + public void setOperator(BinaryOperator operator) { + this.operator = operator; + } + + public Double getValue() { + return value; + } + + public void setValue(Double value) { + this.value = value; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/LocalQoSWSCompositionConstraint.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/LocalQoSWSCompositionConstraint.java new file mode 100644 index 0000000..a687638 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/LocalQoSWSCompositionConstraint.java @@ -0,0 +1,111 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package es.us.isa.qosawarewsbinding.problem; + +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.AbstractWebService; + +import java.io.Serializable; +import java.util.List; + +/** + * + * @author antigravity + */ +public class LocalQoSWSCompositionConstraint extends WSCompositionConstraint implements Serializable { + + private QoSProperty property; + private BinaryOperator operator; + private Double value; + private AbstractWebService task; + + public LocalQoSWSCompositionConstraint(QoSAwareWSCompositionProblem problem, QoSProperty property, + BinaryOperator operator, Double value, AbstractWebService task, boolean hard) { + super(problem); + this.property = property; + this.operator = operator; + this.value = value; + this.task = task; + this.setHard(hard); + } + + @Override + public boolean meets(QoSAwareWSCompositionSolution solution) { + return meetingDistance(solution) <= 0; + } + + @Override + public double meetingDistance(QoSAwareWSCompositionSolution solution) { + es.us.isa.qosawarewsbinding.ConcreteWebService cws = solution.getSelectedService(task); + if (cws == null) + return 1.0; // Should not happen in complete solution + + Double currentVal = (Double) cws.getQoSValue(property); + if (currentVal == null) + return 1.0; // Missing data + + return meetingDistance(currentVal); + } + + private double meetingDistance(Double currentValue) { + double val = currentValue.doubleValue(); + double target = value.doubleValue(); + + // Similar logic to GlobalQoSWSCompositionConstraint + // Using existing logic for consistency + double diff = val - target; + + switch (operator) { + case EQUAL: + return Math.abs(diff); + case DISTINCT: + return (diff == 0) ? 1.0 : 0.0; + case GREATER: + return (val > target) ? 0.0 : (target - val + Double.MIN_VALUE); + case GREATEREQUAL: + return (val >= target) ? 0.0 : (target - val); + case LOWER: + return (val < target) ? 0.0 : (val - target + Double.MIN_VALUE); + case LOWEREQUAL: + return (val <= target) ? 0.0 : (val - target); + default: + return 1.0; + } + } + + public QoSProperty getProperty() { + return property; + } + + public void setProperty(QoSProperty property) { + this.property = property; + } + + public BinaryOperator getOperator() { + return operator; + } + + public void setOperator(BinaryOperator operator) { + this.operator = operator; + } + + public Double getValue() { + return value; + } + + public void setValue(Double value) { + this.value = value; + } + + public AbstractWebService getTask() { + return task; + } + + public void setTask(AbstractWebService task) { + this.task = task; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/LoopPeelingExecutionPathBuilder.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/LoopPeelingExecutionPathBuilder.java new file mode 100644 index 0000000..3eb8e33 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/LoopPeelingExecutionPathBuilder.java @@ -0,0 +1,119 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.Branch; +import es.us.isa.qosawarewsbinding.Loop; +import es.us.isa.qosawarewsbinding.Sequence; +import es.us.isa.qosawarewsbinding.StructuralComponent; +import es.us.isa.qosawarewsbinding.WSCompositionStructure; + +/** + * + * @author japarejo + */ +public class LoopPeelingExecutionPathBuilder implements ExecutionPathsBuilder { + + public Set buildPaths(QoSAwareWSCompositionProblem aThis) { + Set execPaths=new HashSet(); + buildPaths(aThis.getStructure(),execPaths,aThis); + return execPaths; + } + + private void buildPaths(WSCompositionStructure structure, Set execPaths, QoSAwareWSCompositionProblem aThis) { + List previous=new LinkedList(); + List components=((Sequence)structure.getStructure()).getSubComponents(); + buildPaths(previous,components,0,1.0,execPaths,aThis); + } + + private void buildPaths(List previous, List components, int i, double d, Set execPaths, QoSAwareWSCompositionProblem aThis) { + if(i subComponents=((Sequence)comp).getSubComponents(); + List newComponents=createComponentsSec(subComponents,components,1,i); + buildPaths(previous,newComponents,i,d,execPaths,aThis); + }else if(comp instanceof Loop){ + List subComponents=((Loop)comp).getSubComponents(); + List newComponents=null; + for(int j=0;j<=((Loop)comp).getAverageNumberOfIterations();j++){ + newComponents=createComponentsLoops(subComponents,components,j,i); + buildPaths(previous,newComponents,i,d,execPaths,aThis); + } + }else if(comp instanceof Branch) + { + for(StructuralComponent sc:((Branch)comp).getSubComponents()) + { + components.set(i, sc); + buildPaths(previous,components,i,d*((Branch)comp).getBranchProbability(sc),execPaths,aThis); + } + } + }else{ + execPaths.add(new ExecutionPath(aThis, previous,d)); + } + } + + private List createComponentsLoops(List subComponents, List components, int i, int j) { + List result=new LinkedList(); + for(int k=0;k createComponentsSec(List subComponents, List components, int i, int j) { + List result=new LinkedList(); + for(int k=0;k buildPaths(QoSAwareWSCompositionProblem aThis) { + Set execPaths=new HashSet(); + buildPaths(aThis.getStructure(),execPaths,aThis); + return execPaths; + } + + private void buildPaths(WSCompositionStructure structure, Set execPaths,QoSAwareWSCompositionProblem aThis) { + List previous=new LinkedList(); + List components=((Sequence)structure.getStructure()).getSubComponents(); + buildPaths(previous,components,0,1.0,execPaths,aThis); + } + + private void buildPaths(List previous, List components, int i, double d, Set execPaths,QoSAwareWSCompositionProblem aThis) { + if(i subComponents=((Sequence)comp).getSubComponents(); + List newComponents=createComponents(subComponents,components,1,i); + buildPaths(previous,newComponents,i,d,execPaths,aThis); + }else if(comp instanceof Loop){ + List subComponents=((Loop)comp).getSubComponents(); + List newComponents=null; + for(int j=0;j<=((Loop)comp).getAverageNumberOfIterations();j++){ + newComponents=createComponents(subComponents,components,j,i); + buildPaths(previous,newComponents,i,d,execPaths,aThis); + } + }else if(comp instanceof Branch) + { + for(StructuralComponent sc:((Branch)comp).getSubComponents()) + { + components.set(i, sc); + buildPaths(previous,components,i,d*((Branch)comp).getBranchProbability(sc),execPaths,aThis); + } + } + }else{ + execPaths.add(new ExecutionPath(aThis, previous,d)); + } + } + + private List createComponents(List subComponents, List components, int j, int i) { + List result=new LinkedList(); + for(int k=0;k + * NOTA: se recomienda que la descripcin contenga, los parmetros esenciales que + * determinan el tamao concreto de la instancia del problem que el objeto representa + * y todos los parmetros ms que sean necesarios para describir el problem separados + * por comas. + */ + public String getDescription(); + /** This method provides the name of the problem type e.g.: "TSP","SAT","QAP",etc. + * if you are creating your own problem you should ensure its problem is unique + * in your FOM instance. + * @return name of the problem type as string. + */ + public String getProblemType(); + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ProblemReaderAndWriter.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ProblemReaderAndWriter.java new file mode 100644 index 0000000..56d7dbc --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ProblemReaderAndWriter.java @@ -0,0 +1,558 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.Branch; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.Flow; +import es.us.isa.qosawarewsbinding.Loop; +import es.us.isa.qosawarewsbinding.Sequence; +import es.us.isa.qosawarewsbinding.StructuralComponent; +import es.us.isa.qosawarewsbinding.WSCompositionStructure; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.qos.QoSPropertyType; +import es.us.isa.qosawarewsbinding.qos.aggretation.AggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.AverageAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.MaxAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.MaxAverageAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.MinAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.MinAverageAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryPowAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryPowAggregationFunction; +import es.us.isa.qosawarewsbinding.util.MyStringTokenizer; + +/** + * + * @author japarejo + */ +public class ProblemReaderAndWriter { + + public static QoSAwareWSCompositionProblem load(String fileName) + { + File f=new File(fileName); + return load(f); + } + public static void write(String FileName, QoSAwareWSCompositionProblem problem) + { + File f=new File(FileName); + write(f,problem); + } + + private static AbstractWebService getAbstractWebService(String serviceName, QoSAwareWSCompositionProblem result) { + AbstractWebService aws=null; + Set services=result.getStructure().getComponents(); + for(AbstractWebService candidate:services) + if(serviceName.equalsIgnoreCase(candidate.toString())) + aws=candidate; + return aws; + } + + private static AggregationFunction getAggregationFunction(String functionName) { + AggregationFunction result=null; + if(functionName.equalsIgnoreCase("MAX")) + result=MaxAggregationFunction.getInstance(); + else if(functionName.equalsIgnoreCase("MIN")) + result=MinAggregationFunction.getInstance(); + else if(functionName.equalsIgnoreCase("SUM")) + result=SumatoryAggregationFunction.getInstance(); + else if(functionName.equalsIgnoreCase("PRODUCT")) + result=ProductoryAggregationFunction.getInstance(); + else if(functionName.equalsIgnoreCase("POW")) + result=ProductoryPowAggregationFunction.getInstance(); + // New aggregation functions + else if(functionName.equalsIgnoreCase("SUMPOW")) + result=SumatoryPowAggregationFunction.getInstance(); + else if(functionName.equalsIgnoreCase("AVG")) + result=AverageAggregationFunction.getInstance(); + else if(functionName.equalsIgnoreCase("MAXAVG")) + result=MaxAverageAggregationFunction.getInstance(); + else if(functionName.equalsIgnoreCase("MINAVG")) + result=MinAverageAggregationFunction.getInstance(); + return result; + } + + private static Class getStructuralClass(String className) { + Class result=null; + if(className.equalsIgnoreCase("LOOP")) + result=Loop.class; + else if(className.equalsIgnoreCase("BRANCH")) + result=Branch.class; + else if(className.equalsIgnoreCase("SEQUENCE")) + result=Sequence.class; + else if(className.equalsIgnoreCase("FLOW")) + result=Flow.class; + return result; + } + + private static StructuralComponent loadAWS(String line, BufferedReader reader, List awsList) { + StructuralComponent component=null; + line=line.trim(); + if(!line.equals("")) + { + component=searchAWS(line,awsList); + } + return component; + } + + private static StructuralComponent loadBranch(String substring, BufferedReader reader, List awsList) throws IOException { + + StructuralComponent subComponent; + Branch result=new Branch(); + MyStringTokenizer strtok=null; + strtok=new MyStringTokenizer(substring,";",'(',')'); + List probabilities=new LinkedList(); + String value; + while(strtok.hasMoreTokens()) + { + value=strtok.nextToken(); + if(!value.equals(")[")) + probabilities.add(Double.valueOf(value)); + } + int index=0; + do{ + + strtok=new MyStringTokenizer(substring,",",'[',']'); + while(strtok.hasMoreTokens()) + { + subComponent=loadStructureComponent(strtok.nextToken(),reader,awsList); + if(subComponent!=null){ + result.addBranch(subComponent, probabilities.get(index)); + index++; + } + } + if(substring.length()==0 || !(substring.charAt(substring.length()-1)==']')) + substring=reader.readLine(); + }while(substring.length()==0 || !(substring.charAt(substring.length()-1)==']')); + return result; + } + + private static void loadConstraints(QoSAwareWSCompositionProblem result, BufferedReader reader) throws IOException { + String line=reader.readLine(); + while(line.charAt(0)=='%') + line=reader.readLine(); + int nConstraints=Integer.valueOf(line.trim()); + line=reader.readLine(); + if(line.charAt(0)=='%') + line=reader.readLine(); + String stroperator; + BinaryOperator operator; + String propertyName; + QoSProperty property; + String value; + while(line.charAt(0)!='%') + { + line=line.trim(); + MyStringTokenizer strtok=new MyStringTokenizer(line, "(),"); + stroperator=strtok.nextToken("("); + operator=BinaryOperator.valueOf(stroperator); + propertyName=strtok.nextToken(","); + property=result.getQosmodel().getQoSProperty(propertyName); + value=strtok.nextToken(")"); + result.getConstraints().add(new GlobalQoSWSCompositionConstraint(result, property, Double.valueOf(value), operator)); + line=reader.readLine(); + } + } + + private static StructuralComponent loadFlow(String substring, BufferedReader reader, List awsList) { + throw new UnsupportedOperationException("Not yet implemented"); + } + + private static StructuralComponent loadLoop(String substring, BufferedReader reader, List awsList) throws IOException { + String number=substring.substring(0,substring.lastIndexOf(")")); + Integer averageNumberOfIterations=Integer.valueOf(number); + StructuralComponent subComponent; + Loop result=new Loop(averageNumberOfIterations); + substring=substring.substring(substring.lastIndexOf(")")+2); + MyStringTokenizer strtok=null; + do{ + strtok=new MyStringTokenizer(substring,",",'[',']'); + while(strtok.hasMoreTokens()) + { + subComponent=loadStructureComponent(strtok.nextToken(),reader,awsList); + if(subComponent!=null) + result.getSubComponents().add(subComponent); + } + if(substring.length()==0 || !(substring.charAt(substring.length()-1)==']')) + substring=reader.readLine(); + }while(substring.length()==0 || !(substring.charAt(substring.length()-1)==']')); + return result; + } + + private static void loadMarket(QoSAwareWSCompositionProblem result, BufferedReader reader) throws IOException { + Map> market=result.getMarket(); + market.clear(); + String line=reader.readLine(); + while(line.charAt(0)=='%') + line=reader.readLine(); + line=reader.readLine(); + String serviceName=line.trim(); + String cwsName; + String propertyName; + String propertyValue; + AbstractWebService aws=null; + MyStringTokenizer strtok=null; + Set awsSet=null;; + ConcreteWebService cws=null; + while(line.charAt(0)!='%') + { + serviceName=line.trim(); + aws=getAbstractWebService(serviceName,result); + awsSet=new HashSet(); + line=reader.readLine(); + line=reader.readLine(); + while(line.charAt(0)!='-') + { + strtok=new MyStringTokenizer(line, "():,"); + cwsName=strtok.nextToken("("); + cws=new ConcreteWebService(cwsName, aws); + while(strtok.hasMoreTokens()) + { + propertyName=strtok.nextToken(":"); + if(!propertyName.equals(")")){ + propertyValue=strtok.nextToken(","); + try{ + cws.setQoSValue(result.getQosmodel().getQoSProperty(propertyName), Double.valueOf(propertyValue)); + }catch(Exception ex){ + System.out.println(ex); + System.out.println("ON LINE: "+line); + System.out.println("VALUE CAUSING ERROR:"+propertyValue); + } + } + } + awsSet.add(cws); + line=reader.readLine(); + } + market.put(aws, awsSet); + line=reader.readLine(); + } + } + + private static WSCompositionQoSModel loadQoSModel(BufferedReader reader) throws IOException { + WSCompositionQoSModel result=null; + String line=reader.readLine(); + while(line.length()==0 || line.charAt(0)=='%') + line=reader.readLine(); + line=line.trim(); + Set properties; + if(line.equals("QoSModel{")){ + properties=loadQoSModelProperties(reader); + result=new WSCompositionQoSModel(properties); + loadQoSModelAggregationFunctions(reader,result); + loadQoSModelWeights(reader,result); + line=reader.readLine(); + } + return result; + } + + private static void loadQoSModelAggregationFunctions(BufferedReader reader, WSCompositionQoSModel result) throws IOException { + String line=reader.readLine(); + line=line.trim(); + String name; + String function; + QoSProperty property; + String className; + Class myclass; + String functionName; + AggregationFunction aggregationf; + + if(line.equals("AggregationFunctions(")) + { + line=reader.readLine(); + line=line.trim(); + while((!line.equals(")"))) + { + if(line.charAt(line.length()-1)=='{') + { + name=line.substring(0, line.length()-1); + property=result.getQoSProperty(name); + line=reader.readLine(); + line=line.trim(); + while(!line.equals("}")) + { + MyStringTokenizer strtok=new MyStringTokenizer(line,":"); + className=strtok.nextToken(); + functionName=strtok.nextToken(); + myclass=getStructuralClass(className); + aggregationf=getAggregationFunction(functionName); + result.setAggregationFunction(property, myclass, aggregationf); + line=reader.readLine(); + line=line.trim(); + } + } + line=reader.readLine(); + line=line.trim(); + } + } + } + + private static Set loadQoSModelProperties(BufferedReader reader) throws IOException { + Set result=new HashSet(); + QoSProperty property=null; + String line=reader.readLine(); + line=line.trim(); + String name; + String type; + + if(line.equals("Properties{")) + { + line=reader.readLine(); + line=line.trim(); + while((!line.equals("}"))) + { + MyStringTokenizer strtok=new MyStringTokenizer(line, ":-"); // TODO Change the separator € (problems in linux!) + if(strtok.hasMoreTokens()){ + name=strtok.nextToken(":"); + if(strtok.hasMoreTokens()){ + type=strtok.nextToken("-"); // TODO Change the separator € (problems in linux!) + property=new QoSProperty(name,QoSPropertyType.valueOf(type)); + result.add(property); + } + } + line=reader.readLine(); + line=line.trim(); + } + } + return result; + } + + private static void loadQoSModelWeights(BufferedReader reader, WSCompositionQoSModel result) throws IOException { + String line=reader.readLine(); + line=line.trim(); + String name; + String value; + Map qosPropertiesWeights=new HashMap(); + if(line.equals("Weights(")) + { + line=reader.readLine(); + line=line.trim(); + while((!line.equals(")"))) + { + MyStringTokenizer strtok=new MyStringTokenizer(line,":"); + name=strtok.nextToken(); + value=strtok.nextToken(); + qosPropertiesWeights.put(result.getQoSProperty(name),Double.valueOf(value)); + line=reader.readLine(); + line=line.trim(); + } + } + result.setQosPropertiesWeights(qosPropertiesWeights); + } + + + private static StructuralComponent loadSequence(String substring, BufferedReader reader, List awsList) throws IOException { + Sequence result=new Sequence(); + StructuralComponent subComponent; + substring=substring.trim(); + + MyStringTokenizer strtok=null; + do + { + strtok=new MyStringTokenizer(substring,",",'[',']'); + while(strtok.hasMoreTokens()) + { + subComponent=loadStructureComponent(strtok.nextToken(),reader,awsList); + if(subComponent!=null) + result.getSubComponents().add(subComponent); + } + if(substring.length()==0 || !(substring.charAt(substring.length()-1)==']')) + substring=reader.readLine(); + }while(substring.length()==0 || !(substring.charAt(substring.length()-1)==']')); + return result; + } + + private static WSCompositionStructure loadStructure(BufferedReader reader) { + WSCompositionStructure result=null; + String line; + List awsList=new LinkedList(); + try { + line = reader.readLine(); + while(line.charAt(0)=='%') + line=reader.readLine(); + int nAbstractServices=Integer.parseInt(line); + for(int i=0;i awsList) throws IOException + { + StructuralComponent result=null; + line=line.trim(); + if(line.substring(0, Math.min(3, line.length())).equalsIgnoreCase("SEC")) + { + result=loadSequence(line.substring(4),reader,awsList); + }else if(line.substring(0,Math.min(4, line.length())).equalsIgnoreCase("LOOP")){ + result=loadLoop(line.substring(5),reader,awsList); + }else if(line.substring(0,Math.min(6, line.length())).equalsIgnoreCase("BRANCH")){ + result=loadBranch(line.substring(7),reader,awsList); + }else if(line.substring(0,Math.min(3, line.length())).equalsIgnoreCase("FLOW")){ + result=loadFlow(line.substring(5),reader,awsList); + }else{ + result=loadAWS(line,reader,awsList); + } + return result; + } + + private static void printConstraints(PrintWriter writer, List constraints) { + writer.println("%#======================= CONSTRAINTS =============================#"); + writer.println(constraints.size()); + writer.println("% ----------------------"); + for(WSCompositionConstraint constraint:constraints) + { + writer.println(constraint); + } + writer.println("% ----------------------"); + } + + private static void printHeader(PrintWriter writer, String fileName, QoSAwareWSCompositionProblem problem) { + writer.println("%#============================= HEADER ======================================#"); + writer.println("% This file contains an instance of the QoS-Aware Web Services Composition Problem "); + writer.println("% FILE: "+fileName); + writer.println("% Created by: José Antonio Parejo Mestre"); + writer.println("% "+new Date()); + writer.println("% ----------------------"); + writer.println("% Problem Statistics: "); + writer.println("% ----------------------"); + writer.println("% Number of activities: "+problem.getStructure().numberOfActivities()); + int nServices=0; + Collection> values=problem.getMarket().values(); + for(Set services:values) + nServices+=services.size(); + writer.println("% Number of Candidate Services: "+nServices); + writer.println("% Number of Constraints: "+problem.getConstraints().size()); + } + + private static void printMarket(PrintWriter writer, Map> market,WSCompositionQoSModel qosModel) { + writer.println("%#======================= CANDIDATE SERVICES =============================#"); + writer.println("------------------------"); + Set cwservices; + for(AbstractWebService aws:market.keySet()) + { + writer.println(aws); + writer.println("------------------------"); + cwservices=market.get(aws); + for(ConcreteWebService cws:cwservices) + { + writer.print(cws+"("); + for (QoSProperty property : qosModel.getQosProperties()) { + writer.print(property.getName() + ":" + cws.getQoSValue(property) + ","); + } + writer.println(")"); + } + writer.println("------------------------"); + } + } + + private static void printQoSModel(PrintWriter writer, WSCompositionQoSModel qosmodel) { + writer.println("%#======================= QOS MODEL =============================#"); + writer.println(qosmodel); + } + + private static void printStructure(PrintWriter writer, WSCompositionStructure structure) { + writer.println("%#======================= COMPOSITION STRUCTURE =============================#"); + writer.println("% Abstract Services:"); + writer.println("%----------------------"); + writer.println(structure.getComponents().size()); + for(AbstractWebService aws:structure.getComponents()) + writer.println(aws); + writer.println("% CompositionStructure:"); + writer.println("%----------------------"); + writer.println(structure.getStructure().toStructuralString("")); + } + + public static QoSAwareWSCompositionProblem load(File f) { + QoSAwareWSCompositionProblem result=null; + WSCompositionStructure structure=null; + WSCompositionQoSModel qosmodel=null; + Map> market=null; + List constraints; + BufferedReader reader; + String line; + try { + reader = new BufferedReader(new FileReader(f)); + line=reader.readLine(); + line=reader.readLine(); + if(line.equals("% This file contains an instance of the QoS-Aware Web Services Composition Problem ")) + { + // We skip the header: + while(line.charAt(0)=='%' && line.charAt(1)==' ') + line=reader.readLine(); + structure=loadStructure(reader); + qosmodel=loadQoSModel(reader); + result=new QoSAwareWSCompositionProblem(structure, qosmodel); + loadMarket(result,reader); + loadConstraints(result,reader); + } + } catch (FileNotFoundException ex) { + Logger.getLogger(ProblemReaderAndWriter.class.getName()).log(Level.SEVERE, null, ex); + }catch (IOException ex) { + Logger.getLogger(ProblemReaderAndWriter.class.getName()).log(Level.SEVERE, null, ex); + } + if(result!=null) + result.scale(); + return result; + } + + private static StructuralComponent searchAWS(String line, List awsList) { + StructuralComponent result=null; + for(AbstractWebService aws:awsList) + { + if(aws.toString().equals(line)) + result=aws; + } + return result; + } + + private static void write(File f, QoSAwareWSCompositionProblem problem) { + PrintWriter writer; + try { + writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream(f))); + printHeader(writer,f.getName(),problem); + printStructure(writer,problem.getStructure()); + printQoSModel(writer,problem.getQosmodel()); + printMarket(writer,problem.getMarket(),problem.getQosmodel()); + printConstraints(writer,problem.getConstraints()); + writer.close(); + } catch (FileNotFoundException ex) { + Logger.getLogger(ProblemReaderAndWriter.class.getName()).log(Level.SEVERE, null, ex); + } + } + + + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ProviderRelationWSCompositionConstraint.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ProviderRelationWSCompositionConstraint.java new file mode 100644 index 0000000..68d295e --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ProviderRelationWSCompositionConstraint.java @@ -0,0 +1,97 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package es.us.isa.qosawarewsbinding.problem; + +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; +import es.us.isa.qosawarewsbinding.AbstractWebService; + +import es.us.isa.qosawarewsbinding.problem.WSCompositionConstraint; +import java.io.Serializable; +import java.util.List; +import java.util.Set; +import java.util.HashSet; +import java.util.Map; + +/** + * + * @author antigravity + */ +public class ProviderRelationWSCompositionConstraint extends WSCompositionConstraint implements Serializable { + + public enum Type { + SAME_PROVIDER, DIFFERENT_PROVIDER + } + + private Type type; + private List tasks; + private Map serviceProviderMap; // serviceId -> providerId + + public ProviderRelationWSCompositionConstraint(QoSAwareWSCompositionProblem problem, Type type, + List tasks, boolean hard) { + super(problem); + this.type = type; + this.tasks = tasks; + this.setHard(hard); + } + + public void setServiceProviderMap(Map map) { + this.serviceProviderMap = map; + } + + @Override + public boolean meets(QoSAwareWSCompositionSolution solution) { + return meetingDistance(solution) <= 0; + } + + @Override + public double meetingDistance(QoSAwareWSCompositionSolution solution) { + if (tasks == null || tasks.size() < 2) + return 0.0; + + Set providers = new HashSet(); + for (AbstractWebService task : tasks) { + es.us.isa.qosawarewsbinding.ConcreteWebService cws = solution.getSelectedService(task); + if (cws != null) { + String provider = getProvider(cws.getName()); + providers.add(provider); + } + } + + if (type == Type.SAME_PROVIDER) { + // We want 1 provider. Constraints failed by (size - 1) + return Math.max(0.0, providers.size() - 1); + } else if (type == Type.DIFFERENT_PROVIDER) { + // We want N distinct providers (where N = tasks.size()) + return Math.max(0.0, tasks.size() - providers.size()); + } + return 0.0; + } + + private String getProvider(String serviceId) { + // Use the provider map if available (populated from provider_id in the DTO) + if (serviceProviderMap != null && serviceProviderMap.containsKey(serviceId)) { + return serviceProviderMap.get(serviceId); + } + // Fallback: use service ID itself as provider identity + return serviceId; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public List getTasks() { + return tasks; + } + + public void setTasks(List tasks) { + this.tasks = tasks; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/QoSAwareWSCompositionProblem.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/QoSAwareWSCompositionProblem.java new file mode 100644 index 0000000..dfdc5d2 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/QoSAwareWSCompositionProblem.java @@ -0,0 +1,440 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package es.us.isa.qosawarewsbinding.problem; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.WSCompositionStructure; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.qos.QoSPropertyType; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; +import es.us.isa.qosawarewsbinding.solution.Solution; +import es.us.isa.qosawarewsbinding.solution.vector.QoSAwareWSCompositionVectorSolution; + +/** + * + * @author japarejo + */ +public class QoSAwareWSCompositionProblem extends FeasibilityAwareProblem implements Serializable { + + private WSCompositionStructure structure; + private Map> market; + private WSCompositionQoSModel qosmodel; + private List constraints; + private Set expaths; + private static ExecutionPathsBuilder expathBuilder = null; + public boolean scaled; + private Map bestCache = new HashMap(); + private Map worstCache = new HashMap(); + private Map ubCache = new HashMap(); + + public QoSAwareWSCompositionProblem(WSCompositionStructure structure, Map> market, WSCompositionQoSModel qosmodel, List constraints) { + this.structure = structure; + this.market = market; + this.qosmodel = qosmodel; + this.constraints = constraints; + this.expaths = null; + this.scaled = false; + } + + public QoSAwareWSCompositionProblem(WSCompositionStructure structure, WSCompositionQoSModel qosmodel) { + this(structure, new HashMap>(), qosmodel, new LinkedList()); + } + + public int numberOfCandidates(AbstractWebService aws) { + return getMarket().get(aws).size(); + } + + public String getDescription() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public WSCompositionStructure getStructure() { + return structure; + } + + public Map> getMarket() { + return market; + } + + public WSCompositionQoSModel getQosmodel() { + return qosmodel; + } + + public List getConstraints() { + return constraints; + } + + public String toString() { + StringBuffer buffer = new StringBuffer("=== QoS-aware Web Service Composition Problem Instance ===\n"); + buffer.append(getStructure().getStructure().toStructuralString("")); + buffer.append(toStringMarket()); + buffer.append(getQosmodel()); + buffer.append(getConstraints()); + buffer.append("==========================================================\n"); + return buffer.toString(); + + } + + private double scale(double value, double Qmax, double Qmin, QoSProperty property) { + if (Math.abs(Qmax - Qmin) < 1e-12) { + return 0.0; + } + double scaled = (value - Qmin) / (Qmax - Qmin); + if (scaled < 0.0) { + scaled = 0.0; + } else if (scaled > 1.0) { + scaled = 1.0; + } + return scaled; + } + + private String toStringMarket() { + + StringBuffer buffer = new StringBuffer("--- MARKET OF SERVICES ---"); + for (AbstractWebService aws : market.keySet()) { + buffer.append("\nAWS" + aws.toString() + ":"); + for (ConcreteWebService cws : market.get(aws)) { + buffer.append(" S" + cws.getName() + "("); + for (QoSProperty property : getQosmodel().getQosProperties()) { + buffer.append(property.getName() + ":" + cws.getQoSValue(property) + ","); + } + buffer.append(")"); + } + } + buffer.append("\n--------------------------\n"); + return buffer.toString(); + } + + public double feasibilityDistance(Solution sol) { + double value = 0; + for (WSCompositionConstraint constraint : getConstraints()) { + if (constraint.isHard()) { + value += constraint.meetingDistance((QoSAwareWSCompositionSolution) sol); + } + } + return value; + } + + protected double computeFitness(Solution sol) { + double feasibilityDistance = feasibilityDistance(sol); + double result = feasibilityFreeFitness(sol); + if (getPenalizator() != null) { + result = getPenalizator().penalize(result, feasibilityDistance); + } + return result; + } + + public double feasibilityFreeFitness(Solution sol) { + if (!scaled) { + scale(); + } + double total = 0; + + for (QoSProperty property : qosmodel.getQosProperties()) { + Double agg = qosmodel.evaluate((QoSAwareWSCompositionSolution) sol, property, getStructure()); + Double weight = qosmodel.getQoSPropertyWeight(property); + + if (agg != null && weight != null) { + double ub = getQosUb(property); + double denom = ub > 1.0 ? ub : 1.0; + double signedWeight = weight; + if (property.getType() == QoSPropertyType.POSITIVE) { + signedWeight = -signedWeight; + } + total += signedWeight * (agg / denom); + } + } + + return total; + } + + public double candidatesPerService() { + int totalNumberOfCandidates = 0; + for (AbstractWebService aws : getMarket().keySet()) { + totalNumberOfCandidates += getMarket().get(aws).size(); + } + return ((double) (totalNumberOfCandidates)) / ((double) (getMarket().keySet().size())); + } + + public Set getExecutionPaths() { + if (getExpaths() == null) { + if (expathBuilder != null) { + setExpaths(expathBuilder.buildPaths(this)); + } else { + expathBuilder = new LoopUnfoldingExecutionPathsBuilder(); + setExpaths(expathBuilder.buildPaths(this)); + } + } + return getExpaths(); + } + + public boolean isScaled() { + return scaled; + } + + public void scale() { + for (QoSProperty property : getQosmodel().getQosProperties()) { + scale(property); + } + scaled = true; + ubCache.clear(); + //System.out.println("Problem Reescaled!! Current State:"); + //System.out.println(this); + } + + private void scale(QoSProperty property) { + double Qmax = max(property); + double Qmin = min(property); + + // Check if property has a BoundedDomain and use its bounds if available + if (property.getDomain() instanceof es.us.isa.qosawarewsbinding.util.BoundedDomain) { + es.us.isa.qosawarewsbinding.util.BoundedDomain bd = (es.us.isa.qosawarewsbinding.util.BoundedDomain) property + .getDomain(); + if (bd.getMaxBound() != null && bd.getMinBound() != null) { + Qmax = bd.getMaxBound().doubleValue(); + Qmin = bd.getMinBound().doubleValue(); + } + } + + double value = 0; + boolean negative = property.getType() != QoSPropertyType.POSITIVE; + + for (AbstractWebService aws : getMarket().keySet()) { + for (ConcreteWebService cws : getMarket().get(aws)) { + Double objVal = (Double) cws.getQoSValue(property); + if (objVal != null) { + value = objVal; + value = scale(value, Qmax, Qmin, property); + cws.setQoSValue(property, value); + } + } + } + + for (WSCompositionConstraint constraint : constraints) { + if (constraint instanceof GlobalQoSWSCompositionConstraint) { + GlobalQoSWSCompositionConstraint gc = (GlobalQoSWSCompositionConstraint) constraint; + if (gc.getProperty().equals(property)) { + value = gc.getValue(); + value = scale(value, Qmax, Qmin, property); + gc.setValue(value); + } + } else if (constraint instanceof LocalQoSWSCompositionConstraint) { + LocalQoSWSCompositionConstraint lc = (LocalQoSWSCompositionConstraint) constraint; + if (lc.getProperty().equals(property)) { + value = lc.getValue(); + value = scale(value, Qmax, Qmin, property); + lc.setValue(value); + } + } else if (constraint instanceof RangeGlobalQoSWSCompositionConstraint) { + RangeGlobalQoSWSCompositionConstraint rc = (RangeGlobalQoSWSCompositionConstraint) constraint; + if (rc.getProperty().equals(property)) { + double minVal = rc.getMin(); + double maxVal = rc.getMax(); + rc.setMin(scale(minVal, Qmax, Qmin, property)); + rc.setMax(scale(maxVal, Qmax, Qmin, property)); + } + } + } + // Cache best/worst for fitness evaluation + bestCache.put(property, bestValue(property)); + worstCache.put(property, worstValue(property)); + } + + + private double max(QoSProperty property) { + double result = -Double.MAX_VALUE; + boolean found = false; + for (AbstractWebService aws : getMarket().keySet()) { + for (ConcreteWebService cws : market.get(aws)) { + Double candidate = (Double) cws.getQoSValue(property); + if (candidate != null) { + if (candidate > result) { + result = candidate; + } + found = true; + } + } + } + return found ? result : 1.0; // Default max if no values + } + + private double min(QoSProperty property) { + double result = Double.MAX_VALUE; + boolean found = false; + for (AbstractWebService aws : market.keySet()) { + for (ConcreteWebService cws : market.get(aws)) { + Double candidate = (Double) cws.getQoSValue(property); + if (candidate != null) { + if (candidate < result) { + result = candidate; + } + found = true; + } + } + } + return found ? result : 0.0; // Default min if no values + } + + public void setStructure(WSCompositionStructure structure) { + this.structure = structure; + } + + public void setQosmodel(WSCompositionQoSModel qosmodel) { + this.qosmodel = qosmodel; + } + + public void setConstraints(List constraints) { + this.constraints = constraints; + } + + public Set getExpaths() { + return expaths; + } + + public void setExpaths(Set expaths) { + this.expaths = expaths; + } + + public double numberOfExecutedTasks() { + return structure.numberOfExecutedTasks(); + } + + private double getQosUb(QoSProperty property) { + Double cached = ubCache.get(property); + if (cached != null) { + return cached.doubleValue(); + } + + String name = property.getName() != null ? property.getName().toLowerCase() : ""; + boolean isAvailability = name.contains("availability") || name.contains("success"); + + es.us.isa.qosawarewsbinding.qos.aggretation.AggregationFunction seqFn = + qosmodel.getAggregationFunction(property, es.us.isa.qosawarewsbinding.Sequence.class); + es.us.isa.qosawarewsbinding.qos.aggretation.AggregationFunction loopFn = + qosmodel.getAggregationFunction(property, es.us.isa.qosawarewsbinding.Loop.class); + + boolean seqIsProd = seqFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryAggregationFunction + || seqFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryPowAggregationFunction; + boolean loopIsProd = loopFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryAggregationFunction + || loopFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryPowAggregationFunction; + + boolean seqIsSum = seqFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryAggregationFunction + || seqFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.ScaledSumAggregationFunction + || seqFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryPowAggregationFunction; + boolean loopIsSum = loopFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryAggregationFunction + || loopFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.ScaledSumAggregationFunction + || loopFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryPowAggregationFunction; + + double maxVal = 1.0; + double taskSum = 0.0; + for (AbstractWebService aws : market.keySet()) { + double taskMax = 0.0; + for (ConcreteWebService cws : market.get(aws)) { + Double val = (Double) cws.getQoSValue(property); + if (val != null) { + double abs = Math.abs(val.doubleValue()); + if (abs > taskMax) { + taskMax = abs; + } + if (abs > maxVal) { + maxVal = abs; + } + } + } + taskSum += taskMax; + } + + double ub; + if (isAvailability || seqIsProd || loopIsProd) { + ub = 1.0; + } else if (seqIsSum || loopIsSum) { + double loopFactor = 10.0; + ub = Math.max(1.0, taskSum * loopFactor); + } else { + ub = maxVal * 1.5; + } + + ubCache.put(property, ub); + return ub; + } + + public String getProblemType() { + return "QoS-awareCWSBinding"; + } + + public Double bestValue(QoSProperty property) { + QoSAwareWSCompositionSolution solution = computeBestSolution(property); + return qosmodel.evaluate(solution, property, structure); + } + + public Double worstValue(QoSProperty property) { + QoSAwareWSCompositionSolution solution = computeWorstSolution(property); + return qosmodel.evaluate(solution, property, structure); + } + + public QoSAwareWSCompositionSolution computeBestSolution(QoSProperty property) { + QoSAwareWSCompositionVectorSolution result = new QoSAwareWSCompositionVectorSolution(this); + ConcreteWebService bestCandidate = null; + + for (AbstractWebService aws : market.keySet()) { + for (ConcreteWebService cws : market.get(aws)) { + if (bestCandidate == null) { + bestCandidate = cws; + } else { + if (property.getType() == QoSPropertyType.POSITIVE) { + if (((Double) cws.getQoSValue(property)) > ((Double) bestCandidate.getQoSValue(property))) { + bestCandidate = cws; + } + } else { + if (((Double) cws.getQoSValue(property)) < ((Double) bestCandidate.getQoSValue(property))) { + bestCandidate = cws; + } + } + } + } + result.setSelectedService(aws, bestCandidate); + bestCandidate = null; + } + return result; + } + + public QoSAwareWSCompositionSolution computeWorstSolution(QoSProperty property) { + QoSAwareWSCompositionVectorSolution result = new QoSAwareWSCompositionVectorSolution(this); + ConcreteWebService worstCandidate = null; + System.out.println("Search worst solution..."); + for (AbstractWebService aws : market.keySet()) { + for (ConcreteWebService cws : market.get(aws)) { + if (worstCandidate == null) { + worstCandidate = cws; + } else { + + System.out.println("type: " + property.getType() + " worst: " + ((Double) worstCandidate.getQoSValue(property)) + " cws: " + ((Double) cws.getQoSValue(property))); + + if (property.getType() == QoSPropertyType.POSITIVE) { + if (((Double) cws.getQoSValue(property)) < ((Double) worstCandidate.getQoSValue(property))) { + worstCandidate = cws; + } + } else { + if (((Double) cws.getQoSValue(property)) > ((Double) worstCandidate.getQoSValue(property))) { + worstCandidate = cws; + } + } + System.out.println("Updated worst: " + ((Double) worstCandidate.getQoSValue(property))); + } + } + result.setSelectedService(aws, worstCandidate); + worstCandidate = null; + } + return result; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/RangeGlobalQoSWSCompositionConstraint.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/RangeGlobalQoSWSCompositionConstraint.java new file mode 100644 index 0000000..3afbb88 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/RangeGlobalQoSWSCompositionConstraint.java @@ -0,0 +1,94 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package es.us.isa.qosawarewsbinding.problem; + +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; + +import java.io.Serializable; +import java.util.Map; + +/** + * + * @author antigravity + */ +public class RangeGlobalQoSWSCompositionConstraint extends WSCompositionConstraint implements Serializable { + + private QoSProperty property; + private Double min; + private Double max; + private BinaryOperator operator; + + public RangeGlobalQoSWSCompositionConstraint() { + this.operator = BinaryOperator.IN_RANGE; + } + + public RangeGlobalQoSWSCompositionConstraint(QoSAwareWSCompositionProblem problem, QoSProperty property, Double min, + Double max, boolean hard) { + super(problem); + this.property = property; + this.min = min; + this.max = max; + this.operator = BinaryOperator.IN_RANGE; + this.setHard(hard); + } + + @Override + public boolean meets(QoSAwareWSCompositionSolution solution) { + return meetingDistance(solution) <= 0; + } + + @Override + public double meetingDistance(QoSAwareWSCompositionSolution solution) { + Double currentValue = problem.getQosmodel().evaluate(solution, property, problem.getStructure()); + return meetingDistance(currentValue); + } + + private double meetingDistance(Double currentValue) { + if (currentValue == null) + return 1.0; // Distance if null? + double val = currentValue.doubleValue(); + + // Distance is how far from range + if (val < min) + return min - val; + if (val > max) + return val - max; + return 0.0; + } + + public QoSProperty getProperty() { + return property; + } + + public void setProperty(QoSProperty property) { + this.property = property; + } + + public Double getMin() { + return min; + } + + public void setMin(Double min) { + this.min = min; + } + + public Double getMax() { + return max; + } + + public void setMax(Double max) { + this.max = max; + } + + public BinaryOperator getOperator() { + return operator; + } + + public void setOperator(BinaryOperator operator) { + this.operator = operator; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ServicesDespendenceWSCompositionConstraint.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ServicesDespendenceWSCompositionConstraint.java new file mode 100644 index 0000000..b952034 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/ServicesDespendenceWSCompositionConstraint.java @@ -0,0 +1,47 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem; + +import java.io.Serializable; +import java.util.Map; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; + +/** + * + * @author japarejo + */ +public class ServicesDespendenceWSCompositionConstraint extends WSCompositionConstraint implements Serializable{ + + public Map dependences; + + public ServicesDespendenceWSCompositionConstraint(QoSAwareWSCompositionProblem problem, Map dependences) + { + super(problem); + this.dependences=dependences; + } + + @Override + public boolean meets(QoSAwareWSCompositionSolution solution) { + return meetingDistance(solution)==0; + } + + @Override + public double meetingDistance(QoSAwareWSCompositionSolution solution) { + double distance=0; + int present=0; + for(AbstractWebService aws:dependences.keySet()) + { + if(solution.isUsing(aws, dependences.get(aws))) + present++; + } + distance=((double)present)/((double)dependences.keySet().size()); + return distance; + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/SimpleUnfeasibilityPenalizator.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/SimpleUnfeasibilityPenalizator.java new file mode 100644 index 0000000..79f9844 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/SimpleUnfeasibilityPenalizator.java @@ -0,0 +1,14 @@ +package es.us.isa.qosawarewsbinding.problem; + +public class SimpleUnfeasibilityPenalizator implements UnfeasibilityPenalizator { + + @Override + public double penalize(double fitness, double feasibilityDistance) { + if (feasibilityDistance > 0) { + // If infeasible, increase the objective by the distance so it is worse. + return fitness + feasibilityDistance; + } + return fitness; + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/UnfeasibilityPenalizator.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/UnfeasibilityPenalizator.java new file mode 100644 index 0000000..0c8a5d2 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/UnfeasibilityPenalizator.java @@ -0,0 +1,7 @@ +package es.us.isa.qosawarewsbinding.problem; + +public interface UnfeasibilityPenalizator { + + public double penalize(double fitness,double feasibilityDistance); + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionConstraint.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionConstraint.java new file mode 100644 index 0000000..6a46813 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionConstraint.java @@ -0,0 +1,40 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem; + +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; + +/** + * + * @author japarejo + */ +public abstract class WSCompositionConstraint implements Constraint { + + protected QoSAwareWSCompositionProblem problem; + + public WSCompositionConstraint(QoSAwareWSCompositionProblem problem) + { + this.problem=problem; + } + + protected WSCompositionConstraint() { + } + + public abstract boolean meets(QoSAwareWSCompositionSolution solution); + + public abstract double meetingDistance(QoSAwareWSCompositionSolution solution); + + + private boolean hard = true; + + public boolean isHard() { + return hard; + } + + public void setHard(boolean hard) { + this.hard = hard; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionQoSModel.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionQoSModel.java new file mode 100644 index 0000000..fec4e9d --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionQoSModel.java @@ -0,0 +1,174 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + + + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.CompositeStructuralComponent; +import es.us.isa.qosawarewsbinding.StructuralComponent; +import es.us.isa.qosawarewsbinding.WSCompositionStructure; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.qos.aggretation.AggregationFunction; +import es.us.isa.qosawarewsbinding.EmptyComponent; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; + +/** + * + * @author japarejo + */ +public class WSCompositionQoSModel implements Serializable{ + private Set qosProperties; + Map> aggregationFunctions; + private Map qosPropertiesWeights; + + public WSCompositionQoSModel(Set qosProperties) + { + this.qosProperties=qosProperties; + aggregationFunctions=new HashMap>(); + qosPropertiesWeights=new HashMap(); + Double value=1.0/((double)qosProperties.size()); + for(QoSProperty property:qosProperties) + qosPropertiesWeights.put(property, value); + } + + public WSCompositionQoSModel(Map> aggregationFunctions) + { + this.qosProperties=aggregationFunctions.keySet(); + this.aggregationFunctions=aggregationFunctions; + Double value=1.0/((double)this.qosProperties.size()); + for(QoSProperty property:qosProperties) + qosPropertiesWeights.put(property, value); + } + + public AggregationFunction getAggregationFunction(QoSProperty property,Class pclass) + { + AggregationFunction result=null; + Map functions=aggregationFunctions.get(property); + if(functions!=null) + result=functions.get(pclass); + return result; + } + + public void setAggregationFunction(QoSProperty property,Class pclass, AggregationFunction aggregationFunction) + { + Map functions=aggregationFunctions.get(property); + if(functions==null) + { + functions=new HashMap(); + aggregationFunctions.put(property, functions); + } + functions.put(pclass, aggregationFunction); + } + + public Double getQoSPropertyWeight(QoSProperty property) + { + return qosPropertiesWeights.get(property); + } + + public Set getQosProperties() { + return qosProperties; + } + + public void setQosPropertiesWeights(Map qosPropertiesWeights) { + this.qosPropertiesWeights = qosPropertiesWeights; + } + + public QoSProperty getQoSProperty(String name) + { + QoSProperty result=null; + for(QoSProperty property:qosProperties) + if(property.getName().equals(name)) + result=property; + return result; + } + + public Double evaluate(QoSAwareWSCompositionSolution solution,WSCompositionStructure compositionStructure) + { + double result=0; + double qosPropertyAportation; + for(QoSProperty property:qosProperties){ + qosPropertyAportation=evaluate(solution,property,compositionStructure); + result+=qosPropertiesWeights.get(property).doubleValue()*qosPropertyAportation; + } + return result; + } + + public Double evaluate(QoSAwareWSCompositionSolution solution, QoSProperty property,WSCompositionStructure compositionStructure) + { + return evaluate(solution,property,compositionStructure.getStructure()); + } + + public Double evaluate(QoSAwareWSCompositionSolution solution, QoSProperty property, StructuralComponent component) + { + Double result=null; + if(component instanceof AbstractWebService) + result=(Double)solution.getSelectedService((AbstractWebService)component).getQoSValue(property); + else if (component instanceof EmptyComponent) { + if (property.getType() == es.us.isa.qosawarewsbinding.qos.QoSPropertyType.POSITIVE) + result = 1.0; + else + result = 0.0; + } else { + AggregationFunction aggregationFunction=getAggregationFunction(property,component.getClass()); + List partialResults=new LinkedList(); + List ponderations=new LinkedList(); + CompositeStructuralComponent compositeComponent=(CompositeStructuralComponent)component; + Collection subcomponents=compositeComponent.getSubComponents(); + for(StructuralComponent subcomponent:subcomponents){ + if(subcomponent!=null && !subcomponent.isEmpty()){ + partialResults.add(evaluate(solution,property,subcomponent)); + ponderations.add(compositeComponent.getPonderation(subcomponent)); + } + } + result=aggregationFunction.aggregation(partialResults,ponderations); + } + return result; + } + + @Override + public String toString() + { + StringBuffer buffer=new StringBuffer(); + Map functionsPerProperty; + String newline = System.getProperty("line.separator"); + buffer.append("QoSModel{"+newline); + //buffer.append(" "+qosProperties+newline); + buffer.append(" "+"Properties{"+newline); + for(QoSProperty property:qosProperties) + buffer.append(" "+property.toString()+newline); + buffer.append(" }"+newline); + buffer.append(" AggregationFunctions("+newline); + for(QoSProperty property:aggregationFunctions.keySet()){ + buffer.append(" "+property.getName()+"{"+newline); + functionsPerProperty=aggregationFunctions.get(property); + for(Class structureClass:functionsPerProperty.keySet()) + { + buffer.append(" "+structureClass.getSimpleName()+":"+functionsPerProperty.get(structureClass)+newline); + } + buffer.append(" }"+newline); + } + buffer.append(" )"+newline); + buffer.append(" "+"Weights("+newline); + for(QoSProperty property:qosPropertiesWeights.keySet()) + { + buffer.append(" "+property.getName()+":"+qosPropertiesWeights.get(property).doubleValue()+newline); + } + buffer.append(" )"+newline); + buffer.append("}"); + return buffer.toString(); + + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/generator/AbstractProblemGenerator.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/generator/AbstractProblemGenerator.java new file mode 100644 index 0000000..ec8f217 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/generator/AbstractProblemGenerator.java @@ -0,0 +1,24 @@ +package es.us.isa.qosawarewsbinding.problem.generator; + +import es.us.isa.qosawarewsbinding.problem.Problem; +import es.us.isa.qosawarewsbinding.problem.model.ProblemModel; + +public abstract class AbstractProblemGenerator implements ProblemGenerator { + + private ProblemModel problemModel; + + public AbstractProblemGenerator(ProblemModel pmodel) + { + this.problemModel=pmodel; + } + + public ProblemModel getProblemModel() { + return problemModel; + } + + public void setProblemModel(ProblemModel problemModel) { + this.problemModel = problemModel; + } + + +} \ No newline at end of file diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/generator/ProblemGenerator.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/generator/ProblemGenerator.java new file mode 100644 index 0000000..01461bc --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/generator/ProblemGenerator.java @@ -0,0 +1,7 @@ +package es.us.isa.qosawarewsbinding.problem.generator; + +import es.us.isa.qosawarewsbinding.problem.Problem; + +public interface ProblemGenerator { + public X generate(); +} \ No newline at end of file diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/generator/QoSAwareWSCompositionProblemGenerator.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/generator/QoSAwareWSCompositionProblemGenerator.java new file mode 100644 index 0000000..2b37726 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/generator/QoSAwareWSCompositionProblemGenerator.java @@ -0,0 +1,381 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem.generator; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.Branch; +import es.us.isa.qosawarewsbinding.CompositeStructuralComponent; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.Flow; +import es.us.isa.qosawarewsbinding.Loop; +import es.us.isa.qosawarewsbinding.Sequence; +import es.us.isa.qosawarewsbinding.StructuralComponent; +import es.us.isa.qosawarewsbinding.WSCompositionStructure; +import es.us.isa.qosawarewsbinding.problem.BinaryOperator; +import es.us.isa.qosawarewsbinding.problem.GlobalQoSWSCompositionConstraint; +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.problem.WSCompositionConstraint; +import es.us.isa.qosawarewsbinding.problem.WSCompositionQoSModel; +import es.us.isa.qosawarewsbinding.problem.model.GlobalQoSConstraintsModel; +import es.us.isa.qosawarewsbinding.problem.model.QoSAwareWSCompositionProblemConstraintsModel; +import es.us.isa.qosawarewsbinding.problem.model.QoSAwareWSCompositionProblemModel; +import es.us.isa.qosawarewsbinding.problem.model.QoSAwareWSCompositionProblemServicesMarketModel; +import es.us.isa.qosawarewsbinding.problem.model.QoSAwareWSCompositionProblemStructuralModel; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.qos.QoSPropertyType; +import es.us.isa.qosawarewsbinding.qos.aggretation.MaxAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.MinAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryPowAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryAggregationFunction; +import es.us.isa.qosawarewsbinding.solution.vector.QoSAwareWSCompositionVectorSolution; +import es.us.isa.qosawarewsbinding.util.BoundedDomain; +import es.us.isa.qosawarewsbinding.util.DistributionFunction; + +/** + * + * @author japarejo + */ +public class QoSAwareWSCompositionProblemGenerator extends AbstractProblemGenerator{ + + public QoSAwareWSCompositionProblemGenerator(QoSAwareWSCompositionProblemModel model) + { + super(model); + } + + + public QoSAwareWSCompositionProblem generate() + { + WSCompositionStructure structure=generateStructure(); + WSCompositionQoSModel qosModel=generateQoSModel(); + Map> market=generateMarket(structure,qosModel); + List constraints=generateConstraints(market,qosModel); + QoSAwareWSCompositionProblem problem=new QoSAwareWSCompositionProblem(structure,market,qosModel,constraints); + generateGlobalConstraints(constraints ,market,qosModel,problem); + generateAdditionalConstraints(constraints,market,qosModel,problem); + return problem; + } + + public double computeMax(QoSProperty property, Map> market,QoSAwareWSCompositionProblem problem) { + double result=0; + double localExtremeValue; + Double value; + ConcreteWebService cwsSelected=null; + QoSAwareWSCompositionVectorSolution solution=new QoSAwareWSCompositionVectorSolution(problem); + for(AbstractWebService aws:market.keySet()) + { + localExtremeValue=Double.MIN_VALUE; + cwsSelected=null; + for(ConcreteWebService cws:market.get(aws)) + { + value=(Double)cws.getQoSValue(property); + if(value>localExtremeValue || cwsSelected==null){ + localExtremeValue=value; + cwsSelected=cws; + } + } + solution.setSelectedService(aws, cwsSelected); + } + result=problem.getQosmodel().evaluate(solution, property, problem.getStructure().getStructure()); + return result; + } + + public double computeMin(QoSProperty property, Map> market,QoSAwareWSCompositionProblem problem) { + double result=0; + double localExtremeValue; + Double value; + ConcreteWebService cwsSelected=null; + QoSAwareWSCompositionVectorSolution solution=new QoSAwareWSCompositionVectorSolution(problem); + for(AbstractWebService aws:market.keySet()) + { + localExtremeValue=Double.MAX_VALUE; + cwsSelected=null; + for(ConcreteWebService cws:market.get(aws)) + { + value=(Double)cws.getQoSValue(property); + if(value generateConstraints(Map> market, WSCompositionQoSModel qosModel) { + List result=new LinkedList(); + + return result; + } + + public void generateGlobalConstraints(List result, Map> market, WSCompositionQoSModel qosModel,QoSAwareWSCompositionProblem problem) { + QoSAwareWSCompositionProblemModel problemModel=(QoSAwareWSCompositionProblemModel)getProblemModel(); + QoSAwareWSCompositionProblemConstraintsModel constraintsModel=problemModel.getConstraintsModel(); + GlobalQoSConstraintsModel globalConstraintsModel=constraintsModel.getGlobalConstraintsModel(); + int numberOfConstraints=globalConstraintsModel.getNumberOfConstraints(); + double probability=(double)numberOfConstraints/(double)qosModel.getQosProperties().size(); + double min; + double max; + double value; + double percentage; + BinaryOperator operator; + for(QoSProperty property:qosModel.getQosProperties()) + { + if(Math.random() result, Map> market, WSCompositionQoSModel qosModel,QoSAwareWSCompositionProblem problem) { + // TODO: Implement the generation of additional constraints. + } + private Map> generateMarket(WSCompositionStructure structure, WSCompositionQoSModel qosModel) + { + QoSAwareWSCompositionProblemModel problemModel=(QoSAwareWSCompositionProblemModel)getProblemModel(); + QoSAwareWSCompositionProblemServicesMarketModel marketModel=problemModel.getMarketModel(); + return generateMarket(structure,qosModel,marketModel); + } + public Map> generateMarket(WSCompositionStructure structure, WSCompositionQoSModel qosModel,QoSAwareWSCompositionProblemServicesMarketModel marketModel) { + Map> result=new HashMap>(); + Set setCWS=null; + for(AbstractWebService aws:structure.getComponents()) + { + setCWS=generateSubMarket(aws,qosModel,marketModel); + result.put(aws, setCWS); + } + return result; + } + + + + public WSCompositionQoSModel generateQoSModel() { + Set qosProperties=new HashSet(); + QoSProperty cost=new QoSProperty("Cost",new BoundedDomain(0.0,1.0),QoSPropertyType.NEGATIVE); + QoSProperty execTime=new QoSProperty("ExecTime",new BoundedDomain(0.0,1.0),QoSPropertyType.NEGATIVE); + QoSProperty reliability=new QoSProperty("Reliability",new BoundedDomain(0.0,1.0),QoSPropertyType.POSITIVE); + QoSProperty avaliability=new QoSProperty("Availability",new BoundedDomain(0.0,1.0),QoSPropertyType.POSITIVE); + QoSProperty security=new QoSProperty("Security", new BoundedDomain(0.0,1.0),QoSPropertyType.POSITIVE); + qosProperties.add(cost); + qosProperties.add(execTime); + qosProperties.add(reliability); + qosProperties.add(avaliability); + qosProperties.add(security); + WSCompositionQoSModel qosmodel=new WSCompositionQoSModel(qosProperties); + // Weights: + Map qosWeights=new HashMap(); + qosWeights.put(cost, 0.3); + qosWeights.put(execTime, 0.3); + qosWeights.put(reliability, 0.1); + qosWeights.put(avaliability, 0.1); + qosWeights.put(security, 0.2); + qosmodel.setQosPropertiesWeights(qosWeights); + // Aggregation Functions: + // For Cost: + qosmodel.setAggregationFunction(cost, Sequence.class, SumatoryAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(cost, Loop.class, SumatoryAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(cost, Branch.class, SumatoryAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(cost, Flow.class, SumatoryAggregationFunction.getInstance()); + // For ExecTime: + qosmodel.setAggregationFunction(execTime, Sequence.class, SumatoryAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(execTime, Loop.class, SumatoryAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(execTime, Branch.class, SumatoryAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(execTime, Flow.class, MaxAggregationFunction.getInstance()); + // For Reliability: + qosmodel.setAggregationFunction(reliability, Sequence.class, ProductoryAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(reliability, Loop.class, ProductoryPowAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(reliability, Branch.class, SumatoryAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(reliability, Flow.class, ProductoryAggregationFunction.getInstance()); + // For Availability: + qosmodel.setAggregationFunction(avaliability, Sequence.class, ProductoryAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(avaliability, Loop.class, ProductoryPowAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(avaliability, Branch.class, SumatoryAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(avaliability, Flow.class, ProductoryAggregationFunction.getInstance()); + // For Security: + qosmodel.setAggregationFunction(security, Sequence.class, MinAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(security, Loop.class, MinAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(security, Branch.class, SumatoryAggregationFunction.getInstance()); + qosmodel.setAggregationFunction(security, Flow.class, MinAggregationFunction.getInstance()); + return qosmodel; + } + + public CompositeStructuralComponent generateStructuralComponent(QoSAwareWSCompositionProblemStructuralModel structuralModel) { + CompositeStructuralComponent result=null; + // This method must create the structural components associated with the control flow, + // asigning their ponderation (number of iterations in the case of loops, and execution probability for + // each branch in the case of IF-ELSEs. + // Moreover in the case of IF-ELSEs, this method will create a sequence as the structural componen associated with + // each branch + double random=Math.random(); + if(random<(double)(structuralModel.getPercentageLoops()/100.0)){ + int numberOfIterations=structuralModel.getIterationsPerLoop().getValue(); + result=new Loop(numberOfIterations); + }else{ + random=Math.random(); + Branch branch=new Branch(); + CompositeStructuralComponent branch1=new Sequence(); + CompositeStructuralComponent branch2=new Sequence(); + branch.addBranch(branch1, random); + branch.addBranch(branch2, (1.0-random)); + result=branch; + } + return result; + } + + private WSCompositionStructure generateStructure() + { + QoSAwareWSCompositionProblemModel problemModel=(QoSAwareWSCompositionProblemModel)getProblemModel(); + QoSAwareWSCompositionProblemStructuralModel structuralModel=problemModel.getStructuralModel(); + return generateStructure(structuralModel); + } + + public WSCompositionStructure generateStructure(QoSAwareWSCompositionProblemStructuralModel structuralModel) { + WSCompositionStructure structure=null; + int nAbstractWebServices=(100-structuralModel.getPercentageOfControlFlowActivities())*structuralModel.getNumberOfActivities()/100; + AbstractWebService []services=new AbstractWebService[nAbstractWebServices]; + // We create the abstract web services: + for(int i=0;i structuralComponents=new LinkedList(); + int nControlFlowActivities=structuralModel.getPercentageOfControlFlowActivities()*structuralModel.getNumberOfActivities()/100; + for(int i=0;i candidatesToInsertion=new LinkedList(); + candidatesToInsertion.add(root); + // We create another list to store the candidate composite components to the insertion of others that has no subcomponentes: + List emptyCandidatesToInsertion=new LinkedList(); + // We distribute this structures in a control graph (in this case in a control tree) + // having in to account the constraint on the nesting level: + + // We Create a structure to store the nesting level of each component: + Map nestingLevel=new HashMap(); + nestingLevel.put(root, 0); + // We distribute these components: + StructuralComponent currentComponentToDistribute; + CompositeStructuralComponent componentWhereWeNest; + while(!structuralComponents.isEmpty()) + { + currentComponentToDistribute=(StructuralComponent)getRandomElement(structuralComponents); + componentWhereWeNest=(CompositeStructuralComponent)getRandomElement(candidatesToInsertion); + // We impose the maximum nesting level: + while(nestingLevel.get(componentWhereWeNest)>=structuralModel.getMaxNestingLevel()) + componentWhereWeNest=(CompositeStructuralComponent)getRandomElement(candidatesToInsertion); + // We insert the structural component in a randomly selected position: + insertRandomly(currentComponentToDistribute, componentWhereWeNest); + // We updae the nesting level of each component: + updateNestingLevel(currentComponentToDistribute, componentWhereWeNest,nestingLevel,candidatesToInsertion,emptyCandidatesToInsertion); + structuralComponents.remove(currentComponentToDistribute); + } + // Once the control structure is created, we distribute the AbstractWebService invocations: + for(AbstractWebService service:services) + { + if(emptyCandidatesToInsertion.isEmpty()){ + componentWhereWeNest=(CompositeStructuralComponent)getRandomElement(candidatesToInsertion); + insertRandomly(service,componentWhereWeNest); + }else{ + componentWhereWeNest=(CompositeStructuralComponent)getRandomElement(emptyCandidatesToInsertion); + if(componentWhereWeNest instanceof Branch) + insertRandomly(service,(CompositeStructuralComponent) componentWhereWeNest.getSubComponents().get(0)); + else + insertRandomly(service,componentWhereWeNest); + emptyCandidatesToInsertion.remove(componentWhereWeNest); + } + } + AbstractWebService myservice; + int serviceIndex=0; + for(int i=services.length+nControlFlowActivities;i generateSubMarket(AbstractWebService aws, WSCompositionQoSModel qosModel, QoSAwareWSCompositionProblemServicesMarketModel marketModel) { + Set result=new HashSet(); + int numberOfCandidates=Math.max(marketModel.getNumberOfCandidates().getValue(),2); + ConcreteWebService cws=null; + DistributionFunction qosDistribution=null; + for(int i=0;i listOfSubcomponents=componentWhereWeNest.getSubComponents(); + int index=(int)(Math.floor(Math.random()*((double)listOfSubcomponents.size()))); + listOfSubcomponents.add(index, currentComponentToDistribute); + } + + private void updateNestingLevel(StructuralComponent currentComponentToDistribute, CompositeStructuralComponent componentWhereWeNest, Map nestingLevel, List candidatesToInsertion, List emptyCandidatesToInsertion) { + int parentNestingLevel=nestingLevel.get(componentWhereWeNest); + if(currentComponentToDistribute instanceof Loop){ + nestingLevel.put((Loop)currentComponentToDistribute, parentNestingLevel+1); + candidatesToInsertion.add((Loop)currentComponentToDistribute); + emptyCandidatesToInsertion.add((Loop)currentComponentToDistribute); + emptyCandidatesToInsertion.remove(componentWhereWeNest); + }else if(currentComponentToDistribute instanceof Branch){ + for(StructuralComponent subComponent:((Branch)currentComponentToDistribute).getSubComponents()){ + candidatesToInsertion.add((CompositeStructuralComponent)subComponent); + nestingLevel.put((CompositeStructuralComponent)subComponent, parentNestingLevel+1); + } + emptyCandidatesToInsertion.add((CompositeStructuralComponent)currentComponentToDistribute); + emptyCandidatesToInsertion.remove(componentWhereWeNest); + } + } + + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/GlobalQoSConstraintsModel.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/GlobalQoSConstraintsModel.java new file mode 100644 index 0000000..663808f --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/GlobalQoSConstraintsModel.java @@ -0,0 +1,45 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem.model; + +import es.us.isa.qosawarewsbinding.util.DistributionFunction; + + +/** + * + * @author japarejo + */ +public class GlobalQoSConstraintsModel { + private int numberOfConstraints; + private DistributionFunction dfPercentageOfOptimality; + + public GlobalQoSConstraintsModel(int numberOfConstraints, DistributionFunction dfPercentageOfOptimality) + { + this.numberOfConstraints=numberOfConstraints; + this.dfPercentageOfOptimality=dfPercentageOfOptimality; + } + + public int getNumberOfConstraints() { + return numberOfConstraints; + } + + public DistributionFunction getDfPercentageOfOptimality() { + return dfPercentageOfOptimality; + } + + public String toString() + { + StringBuffer buffer=new StringBuffer("GlobalQoSConstraintsModel("); + buffer.append("NumberOfConstraints:"+getNumberOfConstraints()); + buffer.append(",PercentageOfOptimality:"+getDfPercentageOfOptimality()); + buffer.append(")"); + return buffer.toString(); + } + + public void setNumberOfConstraints(int numberOfConstraints) { + this.numberOfConstraints = numberOfConstraints; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/ProblemModel.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/ProblemModel.java new file mode 100644 index 0000000..488f100 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/ProblemModel.java @@ -0,0 +1,5 @@ +package es.us.isa.qosawarewsbinding.problem.model; + +public class ProblemModel { + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemConstraintsModel.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemConstraintsModel.java new file mode 100644 index 0000000..f39ebce --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemConstraintsModel.java @@ -0,0 +1,39 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem.model; + +/** + * + * @author japarejo + */ +public class QoSAwareWSCompositionProblemConstraintsModel { + private GlobalQoSConstraintsModel globalConstraintsModel; + private ServiceDependencesConstraintsModel serviceDependencesConstraintsModel; + + public QoSAwareWSCompositionProblemConstraintsModel(GlobalQoSConstraintsModel globalConstraintsModel,ServiceDependencesConstraintsModel serviceDependencesConstraintsModel) + { + this.globalConstraintsModel=globalConstraintsModel; + this.serviceDependencesConstraintsModel=serviceDependencesConstraintsModel; + } + + public GlobalQoSConstraintsModel getGlobalConstraintsModel() { + return globalConstraintsModel; + } + + public ServiceDependencesConstraintsModel getServiceDependencesConstraintsModel() { + return serviceDependencesConstraintsModel; + } + + @Override + public String toString() + { + StringBuffer buffer=new StringBuffer("ConstraintsModel(\n"); + buffer.append(globalConstraintsModel+"\n"); + buffer.append(serviceDependencesConstraintsModel+"\n"); + buffer.append(";"); + return buffer.toString(); + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemModel.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemModel.java new file mode 100644 index 0000000..681700d --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemModel.java @@ -0,0 +1,62 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem.model; + +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; + +/** + * + * @author japarejo + */ +public class QoSAwareWSCompositionProblemModel extends ProblemModel { + private QoSAwareWSCompositionProblemStructuralModel structuralModel; + private QoSAwareWSCompositionProblemQoSModel qosModel; + private QoSAwareWSCompositionProblemServicesMarketModel marketModel; + private QoSAwareWSCompositionProblemConstraintsModel constraintsModel; + + public QoSAwareWSCompositionProblemModel(QoSAwareWSCompositionProblemStructuralModel structuralModel, QoSAwareWSCompositionProblemQoSModel qosModel,QoSAwareWSCompositionProblemServicesMarketModel marketModel,QoSAwareWSCompositionProblemConstraintsModel constraintsModel) + { + this.structuralModel=structuralModel; + this.marketModel=marketModel; + this.qosModel=qosModel; + this.constraintsModel=constraintsModel; + } + + public QoSAwareWSCompositionProblemStructuralModel getStructuralModel() { + return structuralModel; + } + + public QoSAwareWSCompositionProblemQoSModel getQosModel() { + return qosModel; + } + + public QoSAwareWSCompositionProblemServicesMarketModel getMarketModel() { + return marketModel; + } + + public QoSAwareWSCompositionProblemConstraintsModel getConstraintsModel() { + return constraintsModel; + } + + @Override + public String toString() + { + StringBuffer buffer=new StringBuffer("=== QOS-aware Web Service Composition Problem Model ===\n"); + buffer.append("== Structural Model ==\n"); + buffer.append(structuralModel); + buffer.append("== QoS Model ==\n"); + if(qosModel!=null) + buffer.append(qosModel); + buffer.append("== Market Model ==\n"); + buffer.append(marketModel); + buffer.append("== Constraints Model ==\n"); + if(constraintsModel!=null) + buffer.append(constraintsModel); + buffer.append("=======================================================\n"); + return buffer.toString(); + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemQoSModel.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemQoSModel.java new file mode 100644 index 0000000..237a603 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemQoSModel.java @@ -0,0 +1,5 @@ +package es.us.isa.qosawarewsbinding.problem.model; + +public class QoSAwareWSCompositionProblemQoSModel { + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemServicesMarketModel.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemServicesMarketModel.java new file mode 100644 index 0000000..59a8d57 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemServicesMarketModel.java @@ -0,0 +1,53 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem.model; + +import java.util.HashMap; +import java.util.Map; + +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.util.DistributionFunction; + +/** + * + * @author japarejo + */ +public class QoSAwareWSCompositionProblemServicesMarketModel { + private DistributionFunction numberOfCandidates; + private Map> qosValues; + + public QoSAwareWSCompositionProblemServicesMarketModel(DistributionFunction numberOfCandidates) { + this(numberOfCandidates, new HashMap>()); + } + + public QoSAwareWSCompositionProblemServicesMarketModel(DistributionFunction numberOfCandidates, Map> qosValues) + { + this.numberOfCandidates=numberOfCandidates; + this.qosValues=qosValues; + } + + + public DistributionFunction getNumberOfCandidates() { + return numberOfCandidates; + } + + public Map> getQosValues() { + return qosValues; + } + + @Override + public String toString() + { + StringBuffer buffer=new StringBuffer("ServicesMarquetModel("); + buffer.append("NumberOfCandidates:"+numberOfCandidates+",\n"); + for(QoSProperty property:qosValues.keySet()) + { + buffer.append(" "+property.getName()+":"+qosValues.get(property)+"\n"); + } + buffer.append(")\n"); + return buffer.toString(); + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemStructuralModel.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemStructuralModel.java new file mode 100644 index 0000000..df50a81 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/QoSAwareWSCompositionProblemStructuralModel.java @@ -0,0 +1,81 @@ +package es.us.isa.qosawarewsbinding.problem.model; + +import es.us.isa.qosawarewsbinding.util.DistributionFunction; + +public class QoSAwareWSCompositionProblemStructuralModel { + private int numberOfActivities; + private int numberOfAbstractServices; + private int maxNestingLevel; + private int percentageOfControlFlowActivities; + private double percentageLoops; + private DistributionFunction iterationsPerLoop; + private DistributionFunction branchesPerIf; + + public int getNumberOfActivities() { + return numberOfActivities; + } + + public void setNumberOfActivities(int numberOfActivities) { + this.numberOfActivities = numberOfActivities; + } + + public int getNumberOfAbstractServices() { + return (numberOfActivities*(100-percentageOfControlFlowActivities))/100; + } + + public int getMaxNestingLevel() { + return maxNestingLevel; + } + + public void setMaxNestingLevel(int maxNestingLevel) { + this.maxNestingLevel = maxNestingLevel; + } + + public int getPercentageOfControlFlowActivities() { + return percentageOfControlFlowActivities; + } + + public void setPercentageOfControlFlowActivities(int cyclomaticComplexity) { + this.percentageOfControlFlowActivities = cyclomaticComplexity; + } + + public double getPercentageLoops() { + return percentageLoops; + } + + public void setPercentageLoops(double percentageLoops) { + this.percentageLoops = percentageLoops; + } + + public DistributionFunction getIterationsPerLoop() { + return iterationsPerLoop; + } + + public void setIterationsPerLoop(DistributionFunction iterationsPerLoop) { + this.iterationsPerLoop = iterationsPerLoop; + } + + public DistributionFunction getBranchesPerIf() { + return branchesPerIf; + } + + public void setBranchesPerIf(DistributionFunction branchesPerIf) { + this.branchesPerIf = branchesPerIf; + } + + @Override + public String toString() + { + StringBuffer buffer=new StringBuffer("QoSAwareStructuralModel(\n"); + String prefix=" "; + buffer.append(prefix+"NActivities="+numberOfActivities+",\n"); + buffer.append(prefix+"NAbstractServices="+numberOfAbstractServices+",\n"); + buffer.append(prefix+"PercentageOfControlFlowActivities="+percentageOfControlFlowActivities+",\n"); + buffer.append(prefix+"MaxNestingLevel="+maxNestingLevel+",\n"); + buffer.append(prefix+"PercentageOfLoops="+percentageLoops+",\n"); + buffer.append(prefix+"AverageNumberOfIterations(in Loops)="+iterationsPerLoop+",\n"); + buffer.append(prefix+"AverageNumberOfBranches(in Ifs)="+branchesPerIf+",\n"); + buffer.append(prefix+")\n"); + return buffer.toString(); + } +} \ No newline at end of file diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/ServiceDependencesConstraintsModel.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/ServiceDependencesConstraintsModel.java new file mode 100644 index 0000000..751f5af --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/problem/model/ServiceDependencesConstraintsModel.java @@ -0,0 +1,14 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.problem.model; + +/** + * + * @author japarejo + */ +public class ServiceDependencesConstraintsModel { + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/QoSProperty.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/QoSProperty.java new file mode 100644 index 0000000..d7b3bd4 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/QoSProperty.java @@ -0,0 +1,67 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package es.us.isa.qosawarewsbinding.qos; + +import java.io.Serializable; + +import es.us.isa.qosawarewsbinding.util.Domain; + +/** + * + * @author japarejo + */ +public class QoSProperty implements Serializable { + + private String name; + private Domain domain; + private QoSPropertyType type; + + public QoSProperty(String name, Domain domain, QoSPropertyType type) { + this.name = name; + this.domain = domain; + this.type = type; + } + + public QoSProperty(String name, QoSPropertyType type) { + this(name, new Domain(), type); + } + + public String getName() { + return name; + } + + public Domain getDomain() { + return domain; + } + + public QoSPropertyType getType() { + return type; + } + + @Override + public boolean equals(Object value) + { + boolean result=false; + if(value instanceof QoSProperty) + { + QoSProperty vproperty=(QoSProperty)value; + result=(vproperty.name.equalsIgnoreCase(name)) ; + } + return result; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 23 * hash + (this.name != null ? this.name.hashCode() : 0); + return hash; + } + + @Override + public String toString() + { + return name+":"+type+"-"+domain; // TODO Change the separator € (problems in linux!) + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/QoSPropertyType.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/QoSPropertyType.java new file mode 100644 index 0000000..b6ad042 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/QoSPropertyType.java @@ -0,0 +1,12 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.qos; + +/** + * + * @author japarejo + */ +public enum QoSPropertyType {POSITIVE,NEGATIVE} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/AggregationFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/AggregationFunction.java new file mode 100644 index 0000000..f1fcafb --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/AggregationFunction.java @@ -0,0 +1,19 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.qos.aggretation; + +import java.util.List; + + + +/** + * + * @author JosĂ© Antonio Parejo Maestre + */ +public interface AggregationFunction { + public Double aggregation(List values, List ponderations); + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/AverageAggregationFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/AverageAggregationFunction.java new file mode 100644 index 0000000..1fccddc --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/AverageAggregationFunction.java @@ -0,0 +1,49 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.qos.aggretation; + +import java.util.List; + +/** + * + * @author JosĂ© Antonio Parejo Maestre + */ +public class AverageAggregationFunction extends NumericAggregationFunction { + + private static AverageAggregationFunction _instance=null; + + private AverageAggregationFunction(){} + + public static AverageAggregationFunction getInstance() + { + if(_instance==null) + _instance=new AverageAggregationFunction(); + return _instance; + } + + @Override + public String toString() + { + return "AVG"; + } + + + public Double aggregation(List values, List ponderations) { + Double result=new Double(0.0); + int i=0; + for(Double value:values) + if(value!=null){ + if(ponderations.get(i)!=null) + result=value*ponderations.get(i)+result; + i++; + } + if(values.size()==0) + result = 0.0; + else + result = result/values.size(); + return result; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/MaxAggregationFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/MaxAggregationFunction.java new file mode 100644 index 0000000..31f5a64 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/MaxAggregationFunction.java @@ -0,0 +1,47 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.qos.aggretation; + +import java.util.List; + +/** + * + * @author JosĂ© Antonio Parejo Maestre + */ +public class MaxAggregationFunction implements AggregationFunction { + + private static MaxAggregationFunction _instance=null; + + private MaxAggregationFunction(){} + + public static MaxAggregationFunction getInstance() + { + if(_instance==null) + _instance=new MaxAggregationFunction(); + return _instance; + } + + @Override + public String toString() + { + return "MAX"; + } + + + public Double aggregation(List values, List ponderations) { + Double result=Double.MIN_VALUE; + double candidate=0; + for(Double value:values) + { + candidate=value; + if(candidate>result) + result=candidate; + } + if(values.size()==0) + result=0.0; + return result; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/MaxAverageAggregationFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/MaxAverageAggregationFunction.java new file mode 100644 index 0000000..a206c78 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/MaxAverageAggregationFunction.java @@ -0,0 +1,49 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.qos.aggretation; + +import java.util.List; + +/** + * + * @author JosĂ© Antonio Parejo Maestre + */ +public class MaxAverageAggregationFunction implements AggregationFunction { + + private static MaxAverageAggregationFunction _instance=null; + + private MaxAverageAggregationFunction(){} + + public static MaxAverageAggregationFunction getInstance() + { + if(_instance==null) + _instance=new MaxAverageAggregationFunction(); + return _instance; + } + + @Override + public String toString() + { + return "MAXAVG"; + } + + + public Double aggregation(List values, List ponderations) { + Double result=Double.MIN_VALUE; + double candidate=0; + for(Double value:values) + { + candidate=value; + if(candidate>result) + result=candidate; + } + if(values.size()==0) + result=0.0; + else + result = result/values.size(); + return result; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/MinAggregationFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/MinAggregationFunction.java new file mode 100644 index 0000000..72fad95 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/MinAggregationFunction.java @@ -0,0 +1,50 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.qos.aggretation; + + +import java.util.List; + +/** + * + * @author JosĂ© Antonio Parejo Maestre + */ +public class MinAggregationFunction implements AggregationFunction{ + + private static MinAggregationFunction _instance=null; + + private MinAggregationFunction(){} + + public static MinAggregationFunction getInstance() + { + if(_instance==null) + _instance=new MinAggregationFunction(); + return _instance; + } + + @Override + public String toString() + { + return "MIN"; + } + + + public Double aggregation(List values, List ponderations) { + Double result=Double.MAX_VALUE; + double candidate=0; + for(Double value:values) + { + candidate=value; + if(candidate values, List ponderations) { + Double result=Double.MAX_VALUE; + double candidate=0; + for(Double value:values) + { + candidate=value; + if(candidate implements AggregationFunction { + + protected X obtainFromDouble(double value) + { + Class myclass=this.getClass(); + TypeVariable[] types=myclass.getTypeParameters(); + TypeVariable type=types[0]; + Class paramTypeClass=(Class)type.getGenericDeclaration(); + X result=null; + Class c; + if(Integer.TYPE.isAssignableFrom(paramTypeClass)) + { + result=(X)(new Integer((int)Math.round(value))); + }else if(Double.TYPE.isAssignableFrom(paramTypeClass)) + { + result=(X)(new Double(value)); + }else if(Long.TYPE.isAssignableFrom(paramTypeClass)) + { + result=(X)(new Long((long)Math.round(value))); + }else if(Float.TYPE.isAssignableFrom(paramTypeClass)) + { + result=(X)(new Float(value)); + } + return result; + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/ProductoryAggregationFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/ProductoryAggregationFunction.java new file mode 100644 index 0000000..1a9bcb0 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/ProductoryAggregationFunction.java @@ -0,0 +1,45 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.qos.aggretation; + +import java.util.List; + +/** + * + * @author JosĂ© Antonio Parejo Maestre + */ +public class ProductoryAggregationFunction implements AggregationFunction { + + private static ProductoryAggregationFunction _instance=null; + + private ProductoryAggregationFunction(){} + + public static ProductoryAggregationFunction getInstance() + { + if(_instance==null) + _instance=new ProductoryAggregationFunction(); + return _instance; + } + + @Override + public String toString() + { + return "PRODUCT"; + } + + + public Double aggregation(List values, List ponderations) { + Double result=new Double(1.0); + int i=0; + for(Double value:values){ + result=result*value*ponderations.get(i); + i++; + } + if(values.size()==0) + result=0.0; + return result; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/ProductoryPowAggregationFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/ProductoryPowAggregationFunction.java new file mode 100644 index 0000000..86ac3d8 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/ProductoryPowAggregationFunction.java @@ -0,0 +1,44 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.qos.aggretation; + +import java.util.List; + +/** + * + * @author japarejo + */ +public class ProductoryPowAggregationFunction implements AggregationFunction { + private static ProductoryPowAggregationFunction _instance=null; + + private ProductoryPowAggregationFunction(){} + + public static ProductoryPowAggregationFunction getInstance() + { + if(_instance==null) + _instance=new ProductoryPowAggregationFunction(); + return _instance; + } + + + public Double aggregation(List values, List ponderations) { + double result=1; + for(Double value:values) + if(value!=0) + result*=value; + double ponderation=1; + if(ponderations.size()>0) + ponderation=ponderations.get(0); + result=Math.pow(result, ponderation); + return result; + } + + @Override + public String toString() + { + return "POW"; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/ScaledSumAggregationFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/ScaledSumAggregationFunction.java new file mode 100644 index 0000000..8c222c2 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/ScaledSumAggregationFunction.java @@ -0,0 +1,34 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package es.us.isa.qosawarewsbinding.qos.aggretation; + +import java.util.List; + +/** + * + * @author antigravity + */ +public class ScaledSumAggregationFunction implements AggregationFunction { + + // Singleton? The others were. + private static ScaledSumAggregationFunction instance = new ScaledSumAggregationFunction(); + + public static ScaledSumAggregationFunction getInstance() { + return instance; + } + + @Override + public Double aggregation(List values, List ponderations) { + double result = 0; + for (Double value : values) { + result += value; + } + double factor = 1.0; + if (ponderations != null && !ponderations.isEmpty()) { + factor = ponderations.get(0); + } + return result * factor; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/SumatoryAggregationFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/SumatoryAggregationFunction.java new file mode 100644 index 0000000..3df8fb9 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/SumatoryAggregationFunction.java @@ -0,0 +1,46 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.qos.aggretation; + +import java.util.List; + +/** + * + * @author JosĂ© Antonio Parejo Maestre + */ +public class SumatoryAggregationFunction extends NumericAggregationFunction { + + private static SumatoryAggregationFunction _instance=null; + + private SumatoryAggregationFunction(){} + + public static SumatoryAggregationFunction getInstance() + { + if(_instance==null) + _instance=new SumatoryAggregationFunction(); + return _instance; + } + + @Override + public String toString() + { + return "SUM"; + } + + + public Double aggregation(List values, List ponderations) { + Double result=new Double(0.0); + int i=0; + for(Double value:values) + if(value!=null){ + if(ponderations.get(i)!=null) + result=value*ponderations.get(i)+result; + i++; + } + return result; + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/SumatoryPowAggregationFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/SumatoryPowAggregationFunction.java new file mode 100644 index 0000000..46ea87b --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/SumatoryPowAggregationFunction.java @@ -0,0 +1,44 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.qos.aggretation; + +import java.util.List; + +/** + * + * @author japarejo + */ +public class SumatoryPowAggregationFunction implements AggregationFunction { + + private static SumatoryPowAggregationFunction _instance=null; + + private SumatoryPowAggregationFunction(){} + + public static SumatoryPowAggregationFunction getInstance() + { + if(_instance==null) + _instance=new SumatoryPowAggregationFunction(); + return _instance; + } + + + public Double aggregation(List values, List ponderations) { + double result=0; + for(Double value:values) + result+=value; + double ponderation=1; + if(ponderations.size()>0) + ponderation=ponderations.get(0); + result=Math.pow(result, ponderation); + return result; + } + + public String toString() + { + return "SUMPOW"; + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/AbstractSolution.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/AbstractSolution.java new file mode 100644 index 0000000..a69c51f --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/AbstractSolution.java @@ -0,0 +1,63 @@ +package es.us.isa.qosawarewsbinding.solution; + +import es.us.isa.qosawarewsbinding.problem.Problem; + +public abstract class AbstractSolution implements Solution { + + protected double fitness; + protected T problem; + + public AbstractSolution(T problem) { + this.problem = problem; + fitness = Double.MAX_VALUE; + } + + public double getFitness() { + if (fitness == Double.MAX_VALUE && problem != null) + fitness = problem.fitness(this); + return fitness; + } + + public abstract Solution createRandom(); + + /** + * Getter for property problem. + * + * @return Value of property problem. + */ + public T getProblem() { + return problem; + } + + /** + * Setter for property problem. + * + * @param problem + * New value of property problem. + */ + public void setProblem(T problem) { + this.problem = problem; + } + + /** + * Funcin de ordenacin natural en base al ndice de evaluacin. Por defecto, + * si el objeto no es una solucin se consideran iguales. + */ + + public int compareTo(Object obj) { + int result = 0; + if (obj instanceof Solution) { + if (this.fitness > ((Solution) obj).getFitness()) + result = 1; + else if (this.fitness < ((Solution) obj).getFitness()) + result = -1; + } + return result; + } + + @Override + public String toString() { + return "Fitness:" + fitness; + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/QoSAwareWSCompositionSolution.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/QoSAwareWSCompositionSolution.java new file mode 100644 index 0000000..28df79c --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/QoSAwareWSCompositionSolution.java @@ -0,0 +1,60 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.solution; + +import java.util.Map; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; + +/** + * + * @author japarejo + */ +public abstract class QoSAwareWSCompositionSolution extends + AbstractSolution { + + public QoSAwareWSCompositionSolution(QoSAwareWSCompositionProblem problem) { + super(problem); + } + + public abstract ConcreteWebService getSelectedService(AbstractWebService aws); + + public abstract void setSelectedService(AbstractWebService aws, + ConcreteWebService cws); + + public boolean isUsingServices( + Map cwservices) { + boolean result = true; + int i = 0; + for (AbstractWebService aws : cwservices.keySet()) { + if (!isUsing(aws, cwservices.get(aws))) + return false; + } + return result; + } + + public boolean isUsing(AbstractWebService aws, ConcreteWebService cws) { + return cws == getSelectedService(aws); + } + + @Override + public String toString() { + StringBuffer buffer = new StringBuffer("("); + QoSAwareWSCompositionProblem myproblem = (QoSAwareWSCompositionProblem) problem; + for (AbstractWebService aws : myproblem.getStructure().getComponents()) { + buffer.append("|"); + buffer.append(aws.toString()); + buffer.append("->"); + buffer.append(getSelectedService(aws)); + buffer.append("|"); + } + buffer.append("),"); + buffer.append(super.toString()); + return buffer.toString(); + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/Solution.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/Solution.java new file mode 100644 index 0000000..9a0d7f5 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/Solution.java @@ -0,0 +1,8 @@ +package es.us.isa.qosawarewsbinding.solution; + + +public interface Solution extends Comparable,Cloneable { + public double getFitness(); + public Solution createRandom(); + public int compareTo(Object obj); +} \ No newline at end of file diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/vector/QoSAwareWSCompositionProblemInteger.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/vector/QoSAwareWSCompositionProblemInteger.java new file mode 100644 index 0000000..9a2828c --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/vector/QoSAwareWSCompositionProblemInteger.java @@ -0,0 +1,184 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.solution.vector; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.WSCompositionStructure; +import es.us.isa.qosawarewsbinding.problem.ExecutionPath; +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.problem.WSCompositionConstraint; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.qos.QoSPropertyType; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; +import es.us.isa.qosawarewsbinding.solution.Solution; + +/** + * + * @author japarejo + */ +public class QoSAwareWSCompositionProblemInteger extends QoSAwareWSCompositionProblem { + + private Map abstractWebServicesIndexes; + private QoSAwareWSCompositionProblem problem; + private ConcreteWebService[][] services; + + + public QoSAwareWSCompositionProblemInteger(QoSAwareWSCompositionProblem problem) + { + super(problem.getStructure(),problem.getQosmodel()); + this.problem=problem; + abstractWebServicesIndexes=new HashMap(); + int numberofAbstractServices=problem.getMarket().keySet().size(); + services=new ConcreteWebService[numberofAbstractServices][]; + int i=0; + int j=0; + for(AbstractWebService aws:problem.getMarket().keySet()){ + abstractWebServicesIndexes.put(aws, i); + services[i]=new ConcreteWebService[problem.getMarket().get(aws).size()]; + j=0; + for(ConcreteWebService service:problem.getMarket().get(aws)){ + services[i][j]=service; + j++; + } + i++; + } + } + + @Override + public double feasibilityDistance(Solution sol) { + return problem.feasibilityDistance(sol); + } + + @Override + public double feasibilityFreeFitness(Solution sol) { + return problem.feasibilityFreeFitness(sol); + } + + + @Override + public int numberOfCandidates(AbstractWebService aws) + { + return problem.numberOfCandidates(aws); + } + + @Override + public Map> getMarket() { + return problem.getMarket(); + } + + @Override + public WSCompositionStructure getStructure() + { + return problem.getStructure(); + } + + public int numberOfCandidates(int aws) + { + return services[aws].length; + } + + public ConcreteWebService getService(int aws, int index) + { + return services[aws][index]; + } + + public int getIndex(AbstractWebService aws) + { + return abstractWebServicesIndexes.get(aws); + } + + int getServiceIndex(int aws, ConcreteWebService cws) { + ConcreteWebService []concreteservices=services[aws]; + int result=-1; + for(int i=0;i getExpaths() { + return problem.getExpaths(); + } + + public double numberOfExecutedTasks() + { + return problem.numberOfExecutedTasks(); + } + + @Override + public List getConstraints() { + return problem.getConstraints(); + } + + public Double bestValue(QoSProperty property) { + QoSAwareWSCompositionSolution solution = computeBestSolution(property); + return getQosmodel().evaluate(solution, property, getStructure()); + } + + public Double worstValue(QoSProperty property) { + QoSAwareWSCompositionSolution solution = computeWorstSolution(property); + return getQosmodel().evaluate(solution, property, getStructure()); + } + + public QoSAwareWSCompositionSolution computeBestSolution(QoSProperty property) { + QoSAwareWSCompositionVectorSolution result = new QoSAwareWSCompositionVectorSolution(this); + ConcreteWebService bestCandidate; + ConcreteWebService cws; + Set abstractServices = this.abstractWebServicesIndexes.keySet(); + int i; + for(AbstractWebService aws: abstractServices){ + i = this.abstractWebServicesIndexes.get(aws); + bestCandidate = services[i][0]; + for(int j=0; j ((Double) bestCandidate.getQoSValue(property))) { + bestCandidate = cws; + } + } else { + if (((Double) cws.getQoSValue(property)) < ((Double) bestCandidate.getQoSValue(property))) { + bestCandidate = cws; + } + } + } + result.setSelectedService(aws, bestCandidate); + } + return result; + } + + public QoSAwareWSCompositionSolution computeWorstSolution(QoSProperty property) { + QoSAwareWSCompositionVectorSolution result = new QoSAwareWSCompositionVectorSolution(this); + ConcreteWebService worstCandidate = null; + ConcreteWebService cws; + Set abstractServices = this.abstractWebServicesIndexes.keySet(); + int i; + for(AbstractWebService aws: abstractServices){ + i = this.abstractWebServicesIndexes.get(aws); + worstCandidate = services[i][0]; + for(int j=0; j ((Double) worstCandidate.getQoSValue(property))) { + worstCandidate = cws; + } + } + } + result.setSelectedService(aws, worstCandidate); + } + return result; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/vector/QoSAwareWSCompositionVectorMovement.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/vector/QoSAwareWSCompositionVectorMovement.java new file mode 100644 index 0000000..d510fe5 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/vector/QoSAwareWSCompositionVectorMovement.java @@ -0,0 +1,99 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.solution.vector; + + +/** + * + * @author japarejo + */ +public class QoSAwareWSCompositionVectorMovement { + + private int abstractWebService; + private int previousSelectedService; + private int newSelectedService; + + public QoSAwareWSCompositionVectorMovement(QoSAwareWSCompositionVectorSolutionNavigable solution) + { + + QoSAwareWSCompositionProblemInteger problem=(QoSAwareWSCompositionProblemInteger)solution.getProblem(); + int services=problem.getMarket().keySet().size(); + while(abstractWebService=problem.numberOfCandidates(result.abstractWebService)){ + result.abstractWebService++; + if(result.abstractWebService==services){ + result.abstractWebService=0; + } + while(result.abstractWebService1) + result.newSelectedService=1; + } + result.previousSelectedService=solution.getSelectedService(result.abstractWebService); + return result; + } + + @Override + public String toString() + { + return "["+abstractWebService+","+previousSelectedService+","+newSelectedService+"]"; + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/vector/QoSAwareWSCompositionVectorSolution.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/vector/QoSAwareWSCompositionVectorSolution.java new file mode 100644 index 0000000..837594f --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/solution/vector/QoSAwareWSCompositionVectorSolution.java @@ -0,0 +1,96 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.solution.vector; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; +import es.us.isa.qosawarewsbinding.solution.Solution; + +/** + * + * @author japarejo + */ +public class QoSAwareWSCompositionVectorSolution extends QoSAwareWSCompositionSolution { + + protected int[] selectedServicesIndexes; + + public QoSAwareWSCompositionVectorSolution(QoSAwareWSCompositionProblem problem) + { + super(problem); + if(!(problem instanceof QoSAwareWSCompositionProblemInteger)) + this.problem=new QoSAwareWSCompositionProblemInteger(problem); + selectedServicesIndexes=new int[problem.getMarket().keySet().size()]; + //for(int i=0;i=0 && aws listTasks = new ArrayList(tasks); + for (int i = 0; i < tasks; i++) + if (theproblem.numberOfCandidates(i) > 1) + listTasks.add(new Integer(i)); + int randomAWS = (int) Math.floor(Math.random() + * ((double) listTasks.size())); + int tries = 0; + while (theproblem.numberOfCandidates(randomAWS) < 2 && tries < 5) { + randomAWS = (int) Math.floor(Math.random() + * ((double) listTasks.size())); + tries++; + } + int nCandidates = theproblem.numberOfCandidates(randomAWS); + if (nCandidates > 1) { + List listCandidates = new ArrayList( + nCandidates - 2); + for (int i = 0; i < nCandidates; i++) + if (selectedServicesIndexes[randomAWS] != i) + listCandidates.add(new Integer(i)); + int randomCandidateIndex = (int) Math.floor(Math.random() + * ((double) listCandidates.size())); + result = new QoSAwareWSCompositionVectorSolutionNavigable( + theproblem); + System.arraycopy(selectedServicesIndexes, 0, + result.selectedServicesIndexes, 0, + selectedServicesIndexes.length); + result.selectedServicesIndexes[randomAWS] = listCandidates + .get(randomCandidateIndex); + } + return result; + } + + @Override + public Solution createRandom() { + return new QoSAwareWSCompositionVectorSolutionNavigable( + (QoSAwareWSCompositionProblem) problem); + } + + public void resetNeighbourhood() { + QoSAwareWSCompositionProblemInteger theproblem = (QoSAwareWSCompositionProblemInteger) problem; + int tasks = selectedServicesIndexes.length; + movement = new QoSAwareWSCompositionVectorMovement(this); + neighboursToExplore = 0; + for (int i = 0; i < tasks; i++) { + neighboursToExplore += theproblem.numberOfCandidates(i) - 1; + } + } + + @Override + public String toString() { + return super.toString(); + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/BoundedDomain.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/BoundedDomain.java new file mode 100644 index 0000000..9160f9c --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/BoundedDomain.java @@ -0,0 +1,72 @@ +package es.us.isa.qosawarewsbinding.util; + + +public class BoundedDomain extends IntensionDomain { + + + private ComparableType minBound; + + + private ComparableType maxBound; + + + public BoundedDomain () { + super(); + } + + public BoundedDomain(ComparableType valuemin, ComparableType valuemax) + { + minBound=valuemin; + maxBound=valuemax; + } + + + public ComparableType getMaxBound () { + return maxBound; + } + + public void setMaxBound (ComparableType val) { + this.maxBound = val; + } + + public ComparableType getMinBound () { + return minBound; + } + + public void setMinBound (ComparableType val) { + this.minBound = val; + } + + @Override + public boolean predicate (ComparableType value) { + return minBound.doubleValue()<=value.doubleValue() && maxBound.doubleValue()>=value.doubleValue(); + } + + @Override + public boolean equals(Object value) + { + boolean result=false; + if(value instanceof BoundedDomain) + { + BoundedDomain dom=(BoundedDomain)value; + result=minBound.equals(dom.getMinBound()) && maxBound.equals(dom.getMaxBound()); + } + return result; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 17 * hash + (this.minBound != null ? this.minBound.hashCode() : 0); + hash = 17 * hash + (this.maxBound != null ? this.maxBound.hashCode() : 0); + return hash; + } + + @Override + public String toString() + { + return minBound.getClass().getSimpleName()+"["+minBound.toString()+","+maxBound.toString()+"]"; + } +} + + diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/BoundedDoubleGaussianDistributionFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/BoundedDoubleGaussianDistributionFunction.java new file mode 100644 index 0000000..583e73a --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/BoundedDoubleGaussianDistributionFunction.java @@ -0,0 +1,54 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.util; + +/** + * + * @author japarejo + */ +public class BoundedDoubleGaussianDistributionFunction extends DoubleGaussianDistributionFunction { + private double min; + private double max; + public BoundedDoubleGaussianDistributionFunction(double mean, double standardDeviation) + { + this(mean,standardDeviation,Double.MIN_VALUE,Double.MAX_VALUE); + } + + public BoundedDoubleGaussianDistributionFunction(double mean, double standardDeviation, double min, double max) + { + super(mean,standardDeviation); + this.min=min; + this.max=max; + } + + @Override + public Double getValue() { + Double result=super.getValue(); + if(resultgetMax()) + result=getMax(); + return result; + } + + public double getMin() { + return min; + } + + public void setMin(double min) { + this.min = min; + } + + public double getMax() { + return max; + } + + public void setMax(double max) { + this.max = max; + } + + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/DistributionFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/DistributionFunction.java new file mode 100644 index 0000000..620cfff --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/DistributionFunction.java @@ -0,0 +1,14 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.util; + +/** + * + * @author japarejo + */ +public interface DistributionFunction { + public T getValue(); +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/Domain.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/Domain.java new file mode 100644 index 0000000..4191cf0 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/Domain.java @@ -0,0 +1,11 @@ +package es.us.isa.qosawarewsbinding.util; + +public class Domain { + public Domain() { + } + + public boolean belongs(T value) { + return true; + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/DoubleGaussianDistributionFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/DoubleGaussianDistributionFunction.java new file mode 100644 index 0000000..df2ae45 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/DoubleGaussianDistributionFunction.java @@ -0,0 +1,55 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package es.us.isa.qosawarewsbinding.util; + +import org.apache.commons.math.random.RandomData; +import org.apache.commons.math.random.RandomDataImpl; + + +/** + * + * @author japarejo + */ +public class DoubleGaussianDistributionFunction implements DistributionFunction { + + protected Double mean; + protected Double standarDeviation; + RandomData dataGenerator; + + public DoubleGaussianDistributionFunction(double mean, double standardDeviation) { + this.mean = mean; + this.standarDeviation = standardDeviation; + dataGenerator = new RandomDataImpl(); + } + + + public Double getValue() { + Double result = mean; + result = dataGenerator.nextGaussian(mean, standarDeviation); + return result; + } + + public double getMean() { + return mean; + } + + public void setMean(double mean) { + this.mean = mean; + } + + public double getStandarDeviation() { + return standarDeviation; + } + + public void setStandarDeviation(double standardDeviation) { + this.standarDeviation = standardDeviation; + } + + @Override + public String toString() + { + return "Gaussian(Mean:"+mean+",StandardDeviation:"+standarDeviation+")"; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/DoubleUniformDistributionFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/DoubleUniformDistributionFunction.java new file mode 100644 index 0000000..94f4aea --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/DoubleUniformDistributionFunction.java @@ -0,0 +1,51 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.util; + +/** + * + * @author japarejo + */ +public class DoubleUniformDistributionFunction implements DistributionFunction { + + private Double min; + private Double max; + + public DoubleUniformDistributionFunction(Double min, Double max) + { + this.min=min; + this.max=max; + } + + + public Double getValue() { + return getMin()+Math.random()*(getMax()-getMin()); + + } + + public Double getMin() { + return min; + } + + public void setMin(Double min) { + this.min = min; + } + + public Double getMax() { + return max; + } + + public void setMax(Double max) { + this.max = max; + } + + @Override + public String toString() + { + return "Uniform(Min:"+min+",Max:"+max+")"; + } + +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/IntegerGausssianDistributionFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/IntegerGausssianDistributionFunction.java new file mode 100644 index 0000000..ae6d4a6 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/IntegerGausssianDistributionFunction.java @@ -0,0 +1,55 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.util; + +import org.apache.commons.math.random.RandomData; +import org.apache.commons.math.random.RandomDataImpl; + +/** + * + * @author japarejo + */ +public class IntegerGausssianDistributionFunction implements DistributionFunction{ + + Integer mean; + Double standarDeviation; + RandomData dataGenerator; + + public IntegerGausssianDistributionFunction(Integer mean, Double standarDeviation) + { + this.mean=mean; + this.standarDeviation=standarDeviation; + dataGenerator=new RandomDataImpl(); + } + + + public Integer getValue() { + Integer result = mean; + result = new Integer((int)Math.round((float)(dataGenerator.nextGaussian(mean, standarDeviation)))); + return result; + } + + public Integer getMean() { + return mean; + } + + public void setMean(Integer mean) { + this.mean = mean; + } + + public double getStandarDeviation() { + return standarDeviation; + } + + public void setStandarDeviation(double standardDeviation) { + this.standarDeviation = standardDeviation; + } + + public String toString() + { + return "Gaussian(Mean:"+mean+",StandardDeviation:"+standarDeviation+")"; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/IntegerUniformDistributionFunction.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/IntegerUniformDistributionFunction.java new file mode 100644 index 0000000..d0f1537 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/IntegerUniformDistributionFunction.java @@ -0,0 +1,50 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package es.us.isa.qosawarewsbinding.util; + +/** + * + * @author japarejo + */ +public class IntegerUniformDistributionFunction implements DistributionFunction { + + private Integer min; + private Integer max; + + public IntegerUniformDistributionFunction(Integer min, Integer max) + { + this.min=min; + this.max=max; + } + + + public Integer getValue() { + double value=getMin().doubleValue()+Math.random()*(getMax().doubleValue()-getMin().doubleValue()); + return (int)Math.round(value); + } + + public Integer getMin() { + return min; + } + + public void setMin(Integer min) { + this.min = min; + } + + public Integer getMax() { + return max; + } + + public void setMax(Integer max) { + this.max = max; + } + + @Override + public String toString() + { + return "Uniform(Min:"+min+",Max:"+max+")"; + } +} diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/IntensionDomain.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/IntensionDomain.java new file mode 100644 index 0000000..0688204 --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/IntensionDomain.java @@ -0,0 +1,16 @@ +package es.us.isa.qosawarewsbinding.util; + + +public abstract class IntensionDomain extends Domain { + + public IntensionDomain () { + } + + public boolean belongs (T value) { + return predicate(value); + } + + public abstract boolean predicate (T value); + +} + diff --git a/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/MyStringTokenizer.java b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/MyStringTokenizer.java new file mode 100644 index 0000000..81d8cea --- /dev/null +++ b/engines/many-heuristic/src/main/java/es/us/isa/qosawarewsbinding/util/MyStringTokenizer.java @@ -0,0 +1,70 @@ +package es.us.isa.qosawarewsbinding.util; + +public class MyStringTokenizer { + + int nDelimiters; + String input; + String separator; + char startDelimiter; + char endDelimiter; + /** Creates new MyStringTokenizer */ + public MyStringTokenizer(String entrada,String separador,char startDelimiter, char endDelimiter) + { + this.input=entrada; + this.separator=separador; + nDelimiters=0; + this.startDelimiter=startDelimiter; + this.endDelimiter=endDelimiter; + } + public MyStringTokenizer(String entrada,String separador) { + this(entrada,separador,'(',')'); + } + + public String nextToken(String separador) + { + this.separator=separador; + return nextToken(); + } + public String nextToken() + { + String resultado=""; + int indice=input.indexOf(separator); + if(indice<0){ + resultado=input; + input=""; + return resultado; + } + + nDelimiters=countDelimiters(input.substring(0,indice)); + while(nDelimiters!=0) + { + indice=input.indexOf(separator,indice+separator.length()); + nDelimiters=countDelimiters(input.substring(0,indice+separator.length())); + } + if(indice<0){ + resultado=input; + input=""; + }else + { + resultado=input.substring(0,indice); + input=input.substring(indice+separator.length(),input.length()); + } + return resultado; + } + + public int countDelimiters(String s) + { + int parentesis=0; + for(int i=0;i cost = new QoSProperty("cost", null, QoSPropertyType.NEGATIVE); + Set properties = new HashSet<>(); + properties.add(cost); + WSCompositionQoSModel qosModel = new WSCompositionQoSModel(properties); + + // Mock Problem to return our QoS Model + QoSAwareWSCompositionProblem problem = new QoSAwareWSCompositionProblem(null, qosModel); + + RangeGlobalQoSWSCompositionConstraint c = new RangeGlobalQoSWSCompositionConstraint(problem, cost, 10.0, 20.0, + true); + + // Mock Solution with mocked evaluation + WSCompositionQoSModel mockModel = new WSCompositionQoSModel(properties) { + @Override + public Double evaluate(QoSAwareWSCompositionSolution solution, QoSProperty property, + es.us.isa.qosawarewsbinding.WSCompositionStructure structure) { + return ((MockSolution) solution).getAggregatedValue(property); + } + }; + problem.setQosmodel(mockModel); + // ... rest of test ... use existing var names + MockSolution val15 = new MockSolution(problem); + val15.setAggregatedValue(cost, 15.0); + assertTrue("Should be satisfied inside range", c.meets(val15)); + + MockSolution val10 = new MockSolution(problem); + val10.setAggregatedValue(cost, 10.0); + assertTrue("Should be satisfied at lower bound", c.meets(val10)); + + MockSolution val20 = new MockSolution(problem); + val20.setAggregatedValue(cost, 20.0); + assertTrue("Should be satisfied at upper bound", c.meets(val20)); + + MockSolution val9 = new MockSolution(problem); + val9.setAggregatedValue(cost, 9.9); + assertFalse("Should fail below range", c.meets(val9)); + + assertEquals(0.1, c.meetingDistance(val9), 0.001); + + MockSolution val21 = new MockSolution(problem); + val21.setAggregatedValue(cost, 20.1); + assertFalse("Should fail above range", c.meets(val21)); + assertEquals(0.1, c.meetingDistance(val21), 0.001); + } + + @Test + public void testLocalConstraint() { + QoSProperty cost = new QoSProperty("cost", null, QoSPropertyType.NEGATIVE); + QoSAwareWSCompositionProblem problem = new QoSAwareWSCompositionProblem(null, null); + AbstractWebService task1 = new AbstractWebService("T1"); + + LocalQoSWSCompositionConstraint c = new LocalQoSWSCompositionConstraint(problem, cost, + BinaryOperator.LOWEREQUAL, 10.0, task1, true); + + MockSolution sol = new MockSolution(problem); + ConcreteWebService s1 = new ConcreteWebService("S1", task1); + s1.setQoSValue(cost, 5.0); + sol.setSelectedService(task1, s1); + + assertTrue("5.0 <= 10.0", c.meets(sol)); + + s1.setQoSValue(cost, 15.0); + assertFalse("15.0 <= 10.0 should fail", c.meets(sol)); + assertEquals(5.0, c.meetingDistance(sol), 0.001); + } + + @Test + public void testDependencyConstraint() { + QoSAwareWSCompositionProblem problem = new QoSAwareWSCompositionProblem(null, null); + AbstractWebService t1 = new AbstractWebService("T1"); + AbstractWebService t2 = new AbstractWebService("T2"); + List tasks = Arrays.asList(t1, t2); + + // Different Providers + ProviderRelationWSCompositionConstraint cDiff = new ProviderRelationWSCompositionConstraint( + problem, + ProviderRelationWSCompositionConstraint.Type.DIFFERENT_PROVIDER, + tasks, + true); + + MockSolution sol = new MockSolution(problem); + ConcreteWebService s1 = new ConcreteWebService("s1_P1", t1); + ConcreteWebService s2 = new ConcreteWebService("s2_P2", t2); + + sol.setSelectedService(t1, s1); + sol.setSelectedService(t2, s2); + + assertTrue("Different providers", cDiff.meets(sol)); + + ConcreteWebService s3 = new ConcreteWebService("s3_P1", t2); // Same provider P1 + sol.setSelectedService(t2, s3); + + assertFalse("Same provider but expected different", cDiff.meets(sol)); + + // Same Provider + ProviderRelationWSCompositionConstraint cSame = new ProviderRelationWSCompositionConstraint( + problem, + ProviderRelationWSCompositionConstraint.Type.SAME_PROVIDER, + tasks, + true); + + assertTrue("Same provider P1", cSame.meets(sol)); + + sol.setSelectedService(t2, s2); // P2 + assertFalse("Different provider but expected same", cSame.meets(sol)); + } + + // Stub Solution + static class MockSolution extends QoSAwareWSCompositionSolution { + private Map selection = new HashMap<>(); + private Map aggregated = new HashMap<>(); + + public MockSolution(QoSAwareWSCompositionProblem problem) { + super(problem); + } + + @Override + public ConcreteWebService getSelectedService(AbstractWebService aws) { + return selection.get(aws); + } + + @Override + public void setSelectedService(AbstractWebService aws, ConcreteWebService cws) { + selection.put(aws, cws); + } + + public void setAggregatedValue(QoSProperty p, Double v) { + aggregated.put(p, v); + } + + public Double getAggregatedValue(QoSProperty p) { + return aggregated.get(p); + } + + @Override + public es.us.isa.qosawarewsbinding.solution.Solution createRandom() { + return null; // Not needed + } + + } +} diff --git a/engines/minizinc-csp/Dockerfile b/engines/minizinc-csp/Dockerfile index 2c7f052..d223608 100644 --- a/engines/minizinc-csp/Dockerfile +++ b/engines/minizinc-csp/Dockerfile @@ -3,16 +3,17 @@ FROM node:20-slim # Enable pnpm ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" -RUN corepack enable - -# Install MiniZinc + healthcheck tooling -RUN apt-get update && apt-get install -y --no-install-recommends minizinc curl && rm -rf /var/lib/apt/lists/* +# Install pnpm (via corepack) + MiniZinc + healthcheck tooling +RUN corepack enable \ + && apt-get update \ + && apt-get install -y --no-install-recommends minizinc curl \ + && rm -rf /var/lib/apt/lists/* WORKDIR /app -COPY package.json . +COPY package.json pnpm-lock.yaml ./ COPY tsconfig.json . -RUN pnpm install +RUN pnpm install --frozen-lockfile COPY src/ src/ COPY model/ model/ diff --git a/engines/minizinc-csp/model/composition.mzn b/engines/minizinc-csp/model/composition.mzn index 1da6056..51d1810 100644 --- a/engines/minizinc-csp/model/composition.mzn +++ b/engines/minizinc-csp/model/composition.mzn @@ -33,7 +33,7 @@ int: max_children; array[1..n_nodes, 1..max_children] of int: node_children; array[1..n_nodes] of int: node_n_children; array[1..n_nodes, 1..max_children] of float: node_xor_probs; -array[1..n_nodes] of float: node_loop_iters; % Expected iterations for LOOP nodes +array[1..n_nodes] of int: node_loop_iters; % Expected iterations for LOOP nodes % 4. Aggregation Policies % 1=SUM, 2=PROD, 3=MAX, 4=MIN, 5=WEIGHTED_SUM (for XOR) @@ -114,7 +114,7 @@ constraint forall(i in 1..n_nodes)( % Child is node_children[i,1] let { int: body_idx = node_children[i,1]; - float: iters = node_loop_iters[i]; + int: iters = node_loop_iters[i]; } in % Loop Aggregation restored forall(q in 1..n_qos)( @@ -125,7 +125,7 @@ constraint forall(i in 1..n_nodes)( if pol == AGG_SUM then node_qos[i,q] == body_val * iters elseif pol == AGG_PROD then % Product over iterations: val * val ... * val (iters times) -> pow - node_qos[i,q] == pow(body_val, iters) + node_qos[i,q] == product(k in 1..iters)(body_val) % SCALED_PRODUCT elseif pol == AGG_MAX then node_qos[i,q] == body_val elseif pol == AGG_MIN then node_qos[i,q] == body_val else node_qos[i,q] == body_val * iters @@ -206,7 +206,7 @@ constraint forall(i in 1..n_nodes, j in 1..node_n_children[i])( node_children[i,j] >= 1 /\ node_children[i,j] <= n_nodes ); -constraint forall(i in 1..n_nodes where node_kind[i] != KIND_TASK)( +constraint forall(i in 1..n_nodes where node_kind[i] in {KIND_AND, KIND_XOR, KIND_LOOP})( node_n_children[i] >= 1 ); @@ -232,8 +232,12 @@ constraint forall(i in 1..n_nodes where node_kind[i] == KIND_LOOP)( % Calculate explicit upper bound for objective to prevent Gecode overflow -float: obj_ub = sum(q in 1..n_qos)(abs(qos_weights[q]) * abs(qos_ub[q])); -var -obj_ub..obj_ub: obj_val = sum(q in 1..n_qos)(qos_weights[q] * node_qos[root_id, q]); +float: obj_ub = sum(q in 1..n_qos)(abs(qos_weights[q])); + +% Normalized objective: each feature contribution is divided by its UB +var -obj_ub..obj_ub: obj_val = sum(q in 1..n_qos)( + qos_weights[q] * (node_qos[root_id, q] / max(1.0, qos_ub[q])) +); solve minimize obj_val; diff --git a/engines/minizinc-csp/package-lock.json b/engines/minizinc-csp/package-lock.json new file mode 100644 index 0000000..1f22905 --- /dev/null +++ b/engines/minizinc-csp/package-lock.json @@ -0,0 +1,673 @@ +{ + "name": "minizinc-csp-engine", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "minizinc-csp-engine", + "version": "0.1.0", + "dependencies": { + "ajv": "^8.12.0", + "fastify": "^4.26.1" + }, + "devDependencies": { + "@types/node": "^20.11.19", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@fastify/ajv-compiler": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.6.0.tgz", + "integrity": "sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ==", + "dependencies": { + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "fast-uri": "^2.0.0" + } + }, + "node_modules/@fastify/ajv-compiler/node_modules/fast-uri": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.4.0.tgz", + "integrity": "sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==" + }, + "node_modules/@fastify/error": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.4.1.tgz", + "integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==" + }, + "node_modules/@fastify/fast-json-stringify-compiler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.3.0.tgz", + "integrity": "sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==", + "dependencies": { + "fast-json-stringify": "^5.7.0" + } + }, + "node_modules/@fastify/merge-json-schemas": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz", + "integrity": "sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.19.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz", + "integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==", + "dev": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/avvio": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.4.0.tgz", + "integrity": "sha512-CDSwaxINFy59iNwhYnkvALBwZiTydGkOecZyPkqBpABYR1KqGEsET0VOOYDwtleZSUIdeY36DC2bSZ24CO1igA==", + "dependencies": { + "@fastify/error": "^3.3.0", + "fastq": "^1.17.1" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/fast-content-type-parse": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", + "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==" + }, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stringify": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.16.1.tgz", + "integrity": "sha512-KAdnLvy1yu/XrRtP+LJnxbBGrhN+xXu+gt3EUvZhYGKCr3lFHq/7UFJHHFgmJKoqlh6B40bZLEv7w46B0mqn1g==", + "dependencies": { + "@fastify/merge-json-schemas": "^0.1.0", + "ajv": "^8.10.0", + "ajv-formats": "^3.0.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^2.1.0", + "json-schema-ref-resolver": "^1.0.1", + "rfdc": "^1.2.0" + } + }, + "node_modules/fast-json-stringify/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/fast-json-stringify/node_modules/fast-uri": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.4.0.tgz", + "integrity": "sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==" + }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] + }, + "node_modules/fastify": { + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.29.1.tgz", + "integrity": "sha512-m2kMNHIG92tSNWv+Z3UeTR9AWLLuo7KctC7mlFPtMEVrfjIhmQhkQnT9v15qA/BfVq3vvj134Y0jl9SBje3jXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "dependencies": { + "@fastify/ajv-compiler": "^3.5.0", + "@fastify/error": "^3.4.0", + "@fastify/fast-json-stringify-compiler": "^4.3.0", + "abstract-logging": "^2.0.1", + "avvio": "^8.3.0", + "fast-content-type-parse": "^1.1.0", + "fast-json-stringify": "^5.8.0", + "find-my-way": "^8.0.0", + "light-my-request": "^5.11.0", + "pino": "^9.0.0", + "process-warning": "^3.0.0", + "proxy-addr": "^2.0.7", + "rfdc": "^1.3.0", + "secure-json-parse": "^2.7.0", + "semver": "^7.5.4", + "toad-cache": "^3.3.0" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/find-my-way": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.2.2.tgz", + "integrity": "sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^3.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/json-schema-ref-resolver": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz", + "integrity": "sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/light-my-request": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.14.0.tgz", + "integrity": "sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA==", + "dependencies": { + "cookie": "^0.7.0", + "process-warning": "^3.0.0", + "set-cookie-parser": "^2.4.1" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/pino": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.14.0.tgz", + "integrity": "sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==" + }, + "node_modules/pino/node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] + }, + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ret": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz", + "integrity": "sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" + }, + "node_modules/safe-regex2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-3.1.0.tgz", + "integrity": "sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==", + "dependencies": { + "ret": "~0.4.0" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==" + }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/toad-cache": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", + "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + } + } +} diff --git a/engines/minizinc-csp/src/dzn_builder.ts b/engines/minizinc-csp/src/dzn_builder.ts new file mode 100644 index 0000000..ea4587b --- /dev/null +++ b/engines/minizinc-csp/src/dzn_builder.ts @@ -0,0 +1,419 @@ +export interface DznBuildResult { + dznContent: string; + features: string[]; +} + +export class DznBuilder { + build(instance: any, options: any): DznBuildResult { + const features = this.getFeatures(instance); + const dznContent = this.transformToDZN(instance, features, options); + return { dznContent, features }; + } + + private getFeatures(instance: any): string[] { + const declaredFeatures = (instance.features || []).map((f: any) => f.id); + const featureSet = new Set(declaredFeatures); + + if (instance.aggregation_policies) { + Object.keys(instance.aggregation_policies).forEach((k) => featureSet.add(k)); + } + + if (featureSet.size === 0 && instance.candidates && instance.candidates.length > 0) { + const c = instance.candidates[0]; + const qosData = c.qos || c.features || {}; + Object.keys(qosData).forEach((k) => featureSet.add(k)); + } + + return Array.from(featureSet).sort(); + } + + private transformToDZN(instance: any, features: string[], options: any): string { + const fmt = (arr: any[]) => `[${arr.join(', ')}]`; + const fmt2d = (arr: any[][]) => { + if (arr.length === 0) return `[| |]`; + return `[| ${arr.map((r) => r.join(', ')).join(' | ')} |]`; + }; + + const tasks = instance.tasks || []; + const candidates = instance.candidates || []; + const n_tasks = tasks.length; + const n_candidates = candidates.length; + + const n_qos = features.length; + const featureDefinitions = instance.features || []; + const featureDirection: Record = {}; + featureDefinitions.forEach((f: any) => { + featureDirection[f.id] = (f.direction || 'MINIMIZE').toUpperCase(); + }); + const featureRanges: Record = {}; + featureDefinitions.forEach((f: any) => { + const vr = f.valid_range || {}; + const min = Number(vr.min ?? 0.0); + const max = Number(vr.max ?? 1.0); + featureRanges[f.id] = { min, max }; + }); + const featureMap: Record = {}; + features.forEach((f, i) => (featureMap[f] = i + 1)); + + const scaleValue = (val: number, featId: string): number => { + const range = featureRanges[featId] || { min: 0.0, max: 1.0 }; + const denom = range.max - range.min; + if (Math.abs(denom) < 1e-12 || !Number.isFinite(val)) return 0.0; + let scaled = (val - range.min) / denom; + if (scaled < 0.0) scaled = 0.0; + if (scaled > 1.0) scaled = 1.0; + if (!Number.isFinite(scaled)) return 0.0; + return scaled; + }; + + const FN_MAP: Record = { + sum: 1, + weighted_sum: 5, + product: 2, + max: 3, + min: 4, + scale_by_c: 1, + scaled_sum: 1, + scaled_product: 2, + }; + const DEFAULT_FN = 1; + + const agg_policy: number[][] = []; + + for (const feat of features) { + const pol = (instance.aggregation_policies || {})[feat] || {}; + const compose = pol.compose || {}; + + const row: number[] = []; + row.push(DEFAULT_FN); + row.push(FN_MAP[compose.seq?.fn?.toLowerCase()] || DEFAULT_FN); + row.push(FN_MAP[compose.and?.fn?.toLowerCase()] || FN_MAP.max); + row.push(FN_MAP[compose.xor?.fn?.toLowerCase()] || 5); + row.push(FN_MAP[compose.loop?.fn?.toLowerCase()] || DEFAULT_FN); + agg_policy.push(row); + } + + const taskIdx: Record = {}; + tasks.forEach((t: any, i: number) => (taskIdx[t.id] = i + 1)); + + const providerIdx: Record = {}; + if (instance.providers) { + instance.providers.forEach((p: any, i: number) => (providerIdx[p.id] = i + 1)); + } + + const task_candidates_map: number[][] = Array.from({ length: n_tasks + 1 }, () => []); + const cand_provider: number[] = []; + const cand_qos: number[][] = []; + + candidates.forEach((c: any, i: number) => { + const global_idx = i + 1; + const t_id = taskIdx[c.task_id]; + if (t_id) task_candidates_map[t_id].push(global_idx); + + const qosData = c.qos || c.features || {}; + + let pId = providerIdx[c.provider_id]; + if (!pId) { + pId = -global_idx; + } + cand_provider.push(pId); + + const row: number[] = []; + for (const feat of features) { + let val = qosData[feat]; + if (val === undefined || val === null) val = 0.0; + const scaled = scaleValue(Number(val), feat); + row.push(scaled); + } + cand_qos.push(row); + }); + + let max_cands_per_task = 0; + for (let t = 1; t <= n_tasks; t++) { + if (task_candidates_map[t].length > max_cands_per_task) { + max_cands_per_task = task_candidates_map[t].length; + } + } + if (max_cands_per_task === 0) max_cands_per_task = 1; + + const task_cands: number[][] = []; + const n_task_cands: number[] = []; + + for (let t = 1; t <= n_tasks; t++) { + const cands = task_candidates_map[t]; + n_task_cands.push(cands.length); + const row = [...cands]; + while (row.length < max_cands_per_task) row.push(1); + task_cands.push(row); + } + + const constraints = instance.constraints || []; + + const qos_ub: number[] = []; + for (let f = 0; f < n_qos; f++) { + const featId = features[f]; + const isAvailability = + featId.toLowerCase().includes('availability') || featId.toLowerCase().includes('success'); + + const featDef = featureDefinitions.find((feat: any) => feat.id === featId) || {}; + const featDir = (featDef.direction || 'MINIMIZE').toUpperCase(); + const neutralRaw = + (instance.aggregation_policies?.[featId]?.neutral as number | undefined) ?? + (featDir === 'MAXIMIZE' ? featDef.valid_range?.min : featDef.valid_range?.max); + const neutralScaled = + neutralRaw !== undefined && neutralRaw !== null + ? scaleValue(Number(neutralRaw), featId) + : 0.0; + + let constraintMax = 0.0; + for (const c of constraints) { + if ((c.kind || '').toLowerCase() !== 'attribute_bound') continue; + if (c.attribute_id !== featId) continue; + + if (typeof c.value === 'number') { + constraintMax = Math.max(constraintMax, scaleValue(Number(c.value), featId)); + } else if (c.value && typeof c.value === 'object') { + const minVal = c.value.min; + const maxVal = c.value.max; + if (minVal !== undefined && minVal !== null) { + constraintMax = Math.max(constraintMax, scaleValue(Number(minVal), featId)); + } + if (maxVal !== undefined && maxVal !== null) { + constraintMax = Math.max(constraintMax, scaleValue(Number(maxVal), featId)); + } + } + } + + let maxVal = 1.0; + if (candidates.length > 0 && cand_qos.length > 0) { + maxVal = Math.max(1.0, ...cand_qos.map((row) => Math.abs(row[f]))); + } + + maxVal = Math.max(maxVal, neutralScaled, constraintMax); + + const seqPol = agg_policy[f]?.[1] || 1; + const loopPol = agg_policy[f]?.[4] || 1; + + if (isAvailability || seqPol === 2 || loopPol === 2) { + qos_ub.push(1.0); + } else if (seqPol === 1 || loopPol === 1) { + let taskSum = 0; + for (let t = 1; t <= n_tasks; t++) { + const cands = task_candidates_map[t]; + if (cands.length > 0) { + taskSum += Math.max(...cands.map((cIdx) => Math.abs(cand_qos[cIdx - 1][f]))); + } + } + const loopFactor = 10; + qos_ub.push(Math.max(1.0, taskSum * loopFactor)); + } else { + qos_ub.push(maxVal * 1.5); + } + } + + const nodes: any[] = []; + const traverse = (node: any): number => { + const myIdx = nodes.length + 1; + + let loopIters = 0.0; + if (node.kind === 'LOOP') { + let iters = node.expected_iterations; + if (iters === undefined || iters === null) { + const bounds = node.bounds || {}; + const mn = Number(bounds.min ?? 0); + const mx = Number(bounds.max ?? 0); + if (mx > 0 || mn > 0) { + iters = (mn + mx) / 2.0; + } else { + iters = node.iterations; + } + } + loopIters = Math.round(iters || 1); + } + + const nodeEntry = { + kind: this.getKind(node.kind), + task_id: node.kind === 'TASK' ? taskIdx[node.task_id] : 0, + children: [] as number[], + xor_probs: [] as number[], + loop_iters: loopIters, + }; + nodes.push(nodeEntry); + + if (node.children) { + const isXOR = node.kind === 'XOR'; + for (const child of node.children) { + const childIdx = traverse(child); + nodeEntry.children.push(childIdx); + nodeEntry.xor_probs.push(isXOR ? (child.probability || 0.0) : 0.0); + } + } else if (node.branches) { + for (const br of node.branches) { + const childIdx = traverse(br.child); + nodeEntry.children.push(childIdx); + nodeEntry.xor_probs.push(br.p || 0.0); + } + } else if (node.body) { + const childIdx = traverse(node.body); + nodeEntry.children.push(childIdx); + nodeEntry.xor_probs.push(0.0); + } + return myIdx; + }; + + const root = instance.composition.root; + let root_id = 1; + if (root) root_id = traverse(root); + + const n_nodes = nodes.length; + const max_children = Math.max(1, ...nodes.map((n) => n.children.length)); + const pad = (arr: number[], len: number, val: number) => [ + ...arr, + ...Array(Math.max(0, len - arr.length)).fill(val), + ]; + + const node_kind = nodes.map((n) => n.kind); + const node_task_id = nodes.map((n) => n.task_id); + const node_n_children = nodes.map((n) => n.children.length); + const node_children = nodes.map((n) => pad(n.children, max_children, 0)); + const node_xor_probs = nodes.map((n) => pad(n.xor_probs, max_children, 0.0)); + const node_loop_iters = nodes.map((n) => n.loop_iters); + + const obj = instance.objective || {}; + const weightsObj = obj.weights || {}; + const qos_weights: number[] = []; + for (const feat of features) { + let w = Number(weightsObj[feat] || 0.0); + if (featureDirection[feat] === 'MAXIMIZE') { + w = -w; + } + qos_weights.push(w); + } + + const opMap: Record = { '<=': 1, '>=': 2, '==': 3, '<': 4, '>': 5 }; + + const gc_attr: number[] = []; + const gc_op: number[] = []; + const gc_val: number[] = []; + + const lc_task: number[] = []; + const lc_attr: number[] = []; + const lc_op: number[] = []; + const lc_val: number[] = []; + + const dc_type: number[] = []; + const dc_t1: number[] = []; + const dc_t2: number[] = []; + + for (const c of constraints) { + if (c.hard === false) continue; + + const kind = (c.kind || '').toLowerCase(); + const scope = (c.scope || '').toLowerCase(); + const opRaw = (c.op || '').toLowerCase(); + const type = (c.type || '').toLowerCase(); + + if (kind === 'attribute_bound') { + const attrIdx = featureMap[c.attribute_id]; + const featId = c.attribute_id; + const op = opMap[opRaw]; + const validOp = opMap[c.op] || opMap[opRaw]; + + if (!attrIdx || !validOp) continue; + + if (scope === 'global') { + gc_attr.push(attrIdx); + gc_op.push(validOp); + gc_val.push(scaleValue(c.value, featId)); + } else if (scope === 'local') { + const taskId = c.task_id || (c.tasks && c.tasks[0]); + const tIdx = taskId ? taskIdx[taskId] : undefined; + if (tIdx) { + lc_task.push(tIdx); + lc_attr.push(attrIdx); + lc_op.push(validOp); + lc_val.push(scaleValue(c.value, featId)); + } + } + } else if (kind === 'dependency') { + const tIndices = (c.tasks || []) + .map((tid: string) => taskIdx[tid]) + .filter((i: any) => i); + if (tIndices.length < 2) continue; + + if (type === 'same_provider') { + for (let i = 0; i < tIndices.length - 1; i++) { + dc_type.push(1); + dc_t1.push(tIndices[i]); + dc_t2.push(tIndices[i + 1]); + } + } else if (type === 'different_provider') { + for (let i = 0; i < tIndices.length; i++) { + for (let j = i + 1; j < tIndices.length; j++) { + dc_type.push(2); + dc_t1.push(tIndices[i]); + dc_t2.push(tIndices[j]); + } + } + } + } + } + + + return ` + root_id = ${root_id}; + PROB_EPS = 1e-6; + + n_tasks = ${n_tasks}; + n_candidates = ${n_candidates}; + n_nodes = ${n_nodes}; + n_qos = ${n_qos}; + max_children = ${max_children}; + + max_cands_per_task = ${max_cands_per_task}; + n_task_cands = ${fmt(n_task_cands)}; + task_cands = ${fmt2d(task_cands)}; + + cand_qos = ${fmt2d(cand_qos)}; + candidate_provider = ${fmt(cand_provider)}; + + node_kind = ${fmt(node_kind)}; + node_task_id = ${fmt(node_task_id)}; + node_n_children = ${fmt(node_n_children)}; + node_children = ${fmt2d(node_children)}; + node_xor_probs = ${fmt2d(node_xor_probs)}; + node_loop_iters = ${fmt(node_loop_iters)}; + + agg_policy = ${fmt2d(agg_policy)}; + + qos_weights = ${fmt(qos_weights)}; + qos_ub = ${fmt(qos_ub)}; + + n_global_constraints = ${gc_attr.length}; + gc_attr = ${fmt(gc_attr)}; + gc_op = ${fmt(gc_op)}; + gc_val = ${fmt(gc_val)}; + + n_local_constraints = ${lc_task.length}; + lc_task = ${fmt(lc_task)}; + lc_attr = ${fmt(lc_attr)}; + lc_op = ${fmt(lc_op)}; + lc_val = ${fmt(lc_val)}; + + n_dep_constraints = ${dc_type.length}; + dc_type = ${fmt(dc_type)}; + dc_t1 = ${fmt(dc_t1)}; + dc_t2 = ${fmt(dc_t2)}; + `; + } + + private getKind(k: string): number { + if (k === 'TASK') return 1; + if (k === 'SEQ') return 2; + if (k === 'AND') return 3; + if (k === 'XOR') return 4; + if (k === 'LOOP') return 5; + if (k === 'ELEMENT') return 2; + return 0; + } +} diff --git a/engines/minizinc-csp/src/minizinc_runner.ts b/engines/minizinc-csp/src/minizinc_runner.ts new file mode 100644 index 0000000..dacf830 --- /dev/null +++ b/engines/minizinc-csp/src/minizinc_runner.ts @@ -0,0 +1,53 @@ +import { spawn } from 'child_process'; +import * as fs from 'fs'; + +export interface MiniZincRunResult { + code: number | null; + stdout: string; + stderr: string; + durationMs: number; +} + +export class MiniZincRunner { + async run( + solverName: string, + modelPath: string, + dznContent: string, + tmpDir: string + ): Promise { + const args = ['--solver', solverName, modelPath, '-']; + + if (!fs.existsSync(tmpDir)) { + fs.mkdirSync(tmpDir, { recursive: true }); + } + + const env = { ...process.env, TMPDIR: tmpDir }; + const startTime = Date.now(); + + return new Promise((resolve, reject) => { + const minizinc = spawn('minizinc', args, { env }); + + let stdout = ''; + let stderr = ''; + + minizinc.stdout.on('data', (data) => { + stdout += data.toString(); + }); + minizinc.stderr.on('data', (data) => { + stderr += data.toString(); + }); + + minizinc.on('error', (err) => { + reject(err); + }); + + minizinc.on('close', (code) => { + const durationMs = Date.now() - startTime; + resolve({ code, stdout, stderr, durationMs }); + }); + + minizinc.stdin.write(dznContent); + minizinc.stdin.end(); + }); + } +} diff --git a/engines/minizinc-csp/src/solver.ts b/engines/minizinc-csp/src/solver.ts index 8b4c45d..9e193ed 100644 --- a/engines/minizinc-csp/src/solver.ts +++ b/engines/minizinc-csp/src/solver.ts @@ -1,10 +1,12 @@ -import { spawn } from 'child_process'; import * as path from 'path'; -import * as fs from 'fs'; +import { DznBuilder } from './dzn_builder'; +import { MiniZincRunner } from './minizinc_runner'; export class Solver { private readonly SOLVER_NAME = 'gecode'; private readonly tmpDir = path.resolve(__dirname, '../tmp_minizinc'); + private readonly builder = new DznBuilder(); + private readonly runner = new MiniZincRunner(); async solve(instance: any, options: any): Promise { // 0. Best Practices Validation @@ -21,542 +23,279 @@ export class Solver { } // 1. Identify Features - const features = this.getFeatures(instance); - - // 2. Transform Instance to DZN - const dznContent = this.transformToDZN(instance, features, options); + const { dznContent, features } = this.builder.build(instance, options); // 3. Run MiniZinc // minizinc --solver model.mzn - // The '-' argument tells minizinc to read data from stdin const modelPath = path.resolve(__dirname, '../model/composition.mzn'); - const startTime = Date.now(); - - return new Promise((resolve, reject) => { - const args = ['--solver', this.SOLVER_NAME, modelPath, '-']; - - // Ensure TMPDIR directory exists for MiniZinc - if (!fs.existsSync(this.tmpDir)) { - fs.mkdirSync(this.tmpDir, { recursive: true }); - } - const env = { ...process.env, TMPDIR: this.tmpDir }; - const minizinc = spawn('minizinc', args, { env }); + const runResult = await this.runner.run(this.SOLVER_NAME, modelPath, dznContent, this.tmpDir); + const timeSec = runResult.durationMs / 1000; - let stdout = ''; - let stderr = ''; + if (runResult.code !== 0) { + return { + solution: { + feasible: false, + selection: null, + objective_value: null, + }, + violations: [{ message: `MiniZinc Error: ${runResult.stderr}`, code: 'solver_error' }], + }; + } - minizinc.stdout.on('data', (data) => stdout += data.toString()); - minizinc.stderr.on('data', (data) => stderr += data.toString()); + try { + if ( + runResult.stdout.includes('=====UNSATISFIABLE=====') || + runResult.stdout.includes('model inconsistency detected') + ) { + return { + solution: { + feasible: false, + selection: null, + objective_value: null, + }, + provenance: { + solver: this.SOLVER_NAME, + time_sec: timeSec, + }, + }; + } - // Write DZN content to stdin - minizinc.stdin.write(dznContent); - minizinc.stdin.end(); + const lastBrace = runResult.stdout.lastIndexOf('}'); + const firstBrace = runResult.stdout.indexOf('{'); + if (firstBrace === -1 || lastBrace === -1) { + return { + solution: { + feasible: false, + selection: null, + objective_value: null, + }, + provenance: { + solver: this.SOLVER_NAME, + time_sec: timeSec, + }, + }; + } - minizinc.on('close', async (code) => { - const endTime = Date.now(); - const timeSec = (endTime - startTime) / 1000; + const jsonStr = runResult.stdout.substring(firstBrace, lastBrace + 1); + const result = JSON.parse(jsonStr); - console.log(`MiniZinc process exited with code ${code}`); - if (stdout) console.log(`MiniZinc Stdout: ${stdout}`); - if (stderr) console.error(`MiniZinc Stderr: ${stderr}`); + const taskMap = this.mapTasks(instance); + const candMap = this.mapCandidates(instance); - if (code !== 0) { - return resolve({ - solution: { - feasible: false, - selection: null, - objective_value: null - }, - violations: [{ message: `MiniZinc Error: ${stderr}`, code: "solver_error" }] - }); - } + const selection: Record = {}; - try { - // Check for UNSATISFIABLE - if (stdout.includes("=====UNSATISFIABLE=====") || stdout.includes("model inconsistency detected")) { - return resolve({ - solution: { - feasible: false, - selection: null, - objective_value: null - }, - provenance: { - solver: this.SOLVER_NAME, - time_sec: timeSec - } - }); + if (Array.isArray(result.selected_cand)) { + result.selected_cand.forEach((cIdx: number, idx: number) => { + const taskIdx = idx + 1; + const tId = taskMap[taskIdx]; + const cId = candMap[cIdx.toString()]; + if (tId && cId) { + selection[tId] = cId; } - - // MiniZinc Output Handling - const lastBrace = stdout.lastIndexOf('}'); - const firstBrace = stdout.indexOf('{'); - if (firstBrace === -1 || lastBrace === -1) { - console.warn("No JSON block found in MiniZinc output"); - return resolve({ - solution: { - feasible: false, - selection: null, - objective_value: null - }, - provenance: { - solver: this.SOLVER_NAME, - time_sec: timeSec - } - }); - } - - const jsonStr = stdout.substring(firstBrace, lastBrace + 1); - console.log("Parsing JSON string:", jsonStr); - const result = JSON.parse(jsonStr); - - // Map selected candidates back to IDs - const taskMap = this.mapTasks(instance); // task_idx -> task_id - const candMap = this.mapCandidates(instance); // cand_idx -> cand_id - - const selection: Record = {}; - - if (Array.isArray(result.selected_cand)) { - result.selected_cand.forEach((cIdx: number, idx: number) => { - const taskIdx = idx + 1; - const tId = taskMap[taskIdx]; - const cId = candMap[cIdx.toString()]; - if (tId && cId) { - selection[tId] = cId; - } - }); - } else if (result.selection) { - for (const [tIdx, cIdx] of Object.entries(result.selection)) { - const tId = taskMap[parseInt(tIdx)]; - const cId = candMap[String(cIdx)]; - if (tId && cId) { - selection[tId] = cId; - } - } + }); + } else if (result.selection) { + for (const [tIdx, cIdx] of Object.entries(result.selection)) { + const tId = taskMap[parseInt(tIdx)]; + const cId = candMap[String(cIdx)]; + if (tId && cId) { + selection[tId] = cId; } + } + } - // Map Aggregated Features: Indices -> Feature IDs - const aggregated_features: Record = {}; - if (result.aggregated_features) { - for (const [idxStr, val] of Object.entries(result.aggregated_features)) { - const fIdx = parseInt(idxStr); - // featureMap reverses: name -> idx. We need idx -> name - // features array is sorted: 0-based. fIdx is 1-based. - const featName = features[fIdx - 1]; - if (featName) { - aggregated_features[featName] = Number(val); - } - } + // RECALCULATE RAW AGGREGATED VALUES + // We ignore result.aggregated_features from MiniZinc because they are normalized + const aggregated_features = this.computeRawAggregatedValues(instance, selection, features); + + /* + // OLD NORMALIZED LOGIC + const aggregated_features: Record = {}; + if (result.aggregated_features) { + for (const [idxStr, val] of Object.entries(result.aggregated_features)) { + const fIdx = parseInt(idxStr); + const featName = features[fIdx - 1]; + if (featName) { + aggregated_features[featName] = Number(val); } - - // Handle Normalized Objective Scaling - // If objective was normalized, the result might be scaled. - // But actually minizinc result is just the sum. - // If using normalized weights, the result is in normalized range (0-1 approx). - // We just pass it through. - - resolve({ - solution: { - selection: selection, - objective_value: result.objective_value !== undefined ? result.objective_value : 0, - feasible: true, - aggregated_features: aggregated_features - }, - provenance: { - solver: this.SOLVER_NAME, - time_sec: timeSec - } - }); - } catch (e) { - resolve({ - solution: { - feasible: false, - selection: null, - objective_value: null - }, - violations: [{ message: `Parse Error: ${e} \nOut: ${stdout}`, code: "parser_error" }] - }); } - }); - }); - } - - private getFeatures(instance: any): string[] { - // 1. Collect all declared features from instance.features or fallback to keys in agg policies or candidates - const declaredFeatures = (instance.features || []).map((f: any) => f.id); - const featureSet = new Set(declaredFeatures); - - // Also scan policies - if (instance.aggregation_policies) { - Object.keys(instance.aggregation_policies).forEach(k => featureSet.add(k)); - } + } + */ - // Scan candidates for any extra keys? (Optional, maybe stick to declared to avoid garbage) - // Let's stick to featureSet. If empty, scan one candidate. - if (featureSet.size === 0 && instance.candidates && instance.candidates.length > 0) { - const c = instance.candidates[0]; - const qosData = c.qos || c.features || {}; - Object.keys(qosData).forEach(k => featureSet.add(k)); + return { + solution: { + selection: selection, + objective_value: result.objective_value !== undefined ? result.objective_value : 0, + feasible: true, + aggregated_features: aggregated_features, + }, + provenance: { + solver: this.SOLVER_NAME, + time_sec: timeSec, + }, + }; + } catch (e) { + return { + solution: { + feasible: false, + selection: null, + objective_value: null, + }, + violations: [{ message: `Parse Error: ${e} \nOut: ${runResult.stdout}`, code: 'parser_error' }], + }; } - - return Array.from(featureSet).sort(); // Consistent order } - private transformToDZN(instance: any, features: string[], options: any): string { - // Helper to format arrays - const fmt = (arr: any[]) => `[${arr.join(', ')}]`; - const fmt2d = (arr: any[][]) => { - if (arr.length === 0) return `[| |]`; - // MiniZinc 2D array syntax: [| r1 | r2 | ... |] - return `[| ${arr.map(r => r.join(', ')).join(' | ')} |]`; - }; - - const tasks = instance.tasks || []; - const candidates = instance.candidates || []; - const n_tasks = tasks.length; - const n_candidates = candidates.length; - - // --- 0. Identify QoS Features & Policies --- - // Features passed as argument - const n_qos = features.length; - const featureMap: Record = {}; - features.forEach((f, i) => featureMap[f] = i + 1); - - - - // Aggregation Enums: 1=SUM, 2=PROD, 3=MAX, 4=MIN, 5=WSUM - const FN_MAP: Record = { - "sum": 1, "weighted_sum": 5, "product": 2, "max": 3, "min": 4, - "scale_by_c": 1 // Loop specific: usually means sum * c - }; - const DEFAULT_FN = 1; // Sum - - // Build Aggregation Policy Matrix: [feature_idx, kind_idx] - // Kinds: TASK=1, SEQ=2, AND=3, XOR=4, LOOP=5 - const agg_policy: number[][] = []; - - for (const feat of features) { - const pol = (instance.aggregation_policies || {})[feat] || {}; - const compose = pol.compose || {}; + private computeRawAggregatedValues(instance: any, selection: Record, features: string[]): Record { + // 1. Build a map of candidates for quick lookup + const candidateMap: Record = {}; + if (Array.isArray(instance.candidates)) { + instance.candidates.forEach((c: any) => { + candidateMap[c.id] = c; + }); + } - const row: number[] = []; - // 1. TASK (N/A really, but filler) - row.push(DEFAULT_FN); + // 2. Recursive traversal + const traverse = (node: any, featId: string): number => { + if (!node) return 0; - // 2. SEQ - row.push(FN_MAP[compose.seq?.fn] || DEFAULT_FN); + const kind = node.kind || ''; - // 3. AND - row.push(FN_MAP[compose.and?.fn] || DEFAULT_FN); // Usually MAX or SUM + if (kind === 'TASK') { + const taskId = node.task_id; + const candId = selection[taskId]; + if (!candId) return 0; // Should not happen if feasible - // 4. XOR - // Default XOR to WSUM (5) unless specified - row.push(FN_MAP[compose.xor?.fn] || 5); + const cand = candidateMap[candId]; + if (!cand) return 0; - // 5. LOOP - row.push(FN_MAP[compose.loop?.fn] || DEFAULT_FN); + const qos = cand.qos || cand.features || {}; + let val = qos[featId]; + if (val === undefined || val === null) return 0; // Default to 0 if missing + return Number(val); + } - agg_policy.push(row); - } + // Composite nodes + const pol = instance.aggregation_policies?.[featId]?.compose?.[kind.toLowerCase()] || {}; + const fn = (pol.fn || 'SUM').toUpperCase(); + + let children: any[] = []; + if (kind === 'LOOP') { + // Loop has body + // Loop iterations + let iters = node.expected_iterations; + if (iters === undefined || iters === null) { + const bounds = node.bounds || {}; + const mn = Number(bounds.min ?? 0); + const mx = Number(bounds.max ?? 0); + if (mx > 0 || mn > 0) { + iters = (mn + mx) / 2.0; + } else { + iters = node.iterations || 1; + } + } + const loopIters = Number(iters); + const bodyVal = traverse(node.body, featId); - // --- 1. Map Tasks & Providers --- - const taskIdx: Record = {}; - tasks.forEach((t: any, i: number) => taskIdx[t.id] = i + 1); + // Default loop aggregation logic matching engines + // If SUM/SCALED_SUM -> val * iters + // If PROD -> val ^ iters (SCALED_PRODUCT) + // If MAX/MIN -> val - const providerIdx: Record = {}; - if (instance.providers) { - instance.providers.forEach((p: any, i: number) => providerIdx[p.id] = i + 1); - } + if (fn === 'SUM' || fn === 'SCALED_SUM') return bodyVal * loopIters; + if (fn === 'PRODUCT' || fn === 'SCALED_PRODUCT') return Math.pow(bodyVal, loopIters); + if (fn === 'MAX' || fn === 'MIN') return bodyVal; - // --- 2. Candidates & QoS Matrix --- - const task_candidates_map: number[][] = Array.from({ length: n_tasks + 1 }, () => []); - const cand_provider: number[] = []; - const cand_qos: number[][] = []; // [cand][feat] - - candidates.forEach((c: any, i: number) => { - const global_idx = i + 1; - const t_id = taskIdx[c.task_id]; - if (t_id) task_candidates_map[t_id].push(global_idx); - - cand_provider.push(providerIdx[c.provider_id] || 0); - - // QoS Values - support both 'qos' and 'features' property names - const qosData = c.qos || c.features || {}; - const row: number[] = []; - for (const feat of features) { - let val = qosData[feat]; - // Handle missing values? Default to 0? Or Worst case? - // For logic, 0.0 is safest default unless it's reliability (should be 1?) - // Trying to be smart: if 'product' agg, default to 1? - // For now, default 0.0. User should provide complete data. - if (val === undefined || val === null) val = 0.0; - row.push(Number(val)); + // Fallback + return bodyVal * loopIters; } - cand_qos.push(row); - }); - // Max candidates per task - let max_cands_per_task = 0; - for (let t = 1; t <= n_tasks; t++) { - if (task_candidates_map[t].length > max_cands_per_task) { - max_cands_per_task = task_candidates_map[t].length; + // SEQ, AND, XOR + let explicitProbs: number[] = []; + if (node.children) { + children = node.children; + } else if (node.branches) { + children = node.branches.map((b: any) => b.child); + explicitProbs = node.branches.map((b: any) => b.p || 0); } - } - if (max_cands_per_task === 0) max_cands_per_task = 1; - const task_cands: number[][] = []; - const n_task_cands: number[] = []; - - for (let t = 1; t <= n_tasks; t++) { - const cands = task_candidates_map[t]; - n_task_cands.push(cands.length); - const row = [...cands]; - while (row.length < max_cands_per_task) row.push(1); // Pad - task_cands.push(row); - } - - // --- 3. Compute Bounds (QoS UB) --- - // Use tighter bounds to avoid Gecode float overflow - // For SUM aggregation: max possible is sum of max candidates per task - // We compute a reasonable upper bound based on actual data - const qos_ub: number[] = []; - for (let f = 0; f < n_qos; f++) { - // Check max value in candidates - let maxVal = 1.0; - if (candidates.length > 0 && cand_qos.length > 0) { - maxVal = Math.max(1.0, ...cand_qos.map(row => Math.abs(row[f]))); + const childVals = children.map(c => traverse(c, featId)); + + if (kind === 'XOR') { + // XOR uses probability weighted sum usually, or MAX/MIN + // If fn is MAX -> max(childVals) + // If fn is MIN -> min(childVals) + // If fn is SCALED_SUM (default for XOR) -> sum(prob * val) + + if (fn === 'MAX') return Math.max(...childVals); + if (fn === 'MIN') return Math.min(...childVals); + + // Default Weighted Sum + let sum = 0; + for (let i = 0; i < childVals.length; i++) { + // If explicit probs exist (from branches), use them + // If not (e.g. from children list), assume equal? XOR usually has branches with probs. + // The JSON usually has `branches` for XOR. + let p = explicitProbs[i] !== undefined ? explicitProbs[i] : (1.0 / childVals.length); + sum += p * childVals[i]; + } + return sum; } - // Check aggregation policy for SEQ/LOOP (columns 1 and 4 in 0-based row) - // Indices in MZN: SEQ=2, LOOP=5. In 0-based array: 1, 4. - const seqPol = agg_policy[f]?.[1] || 1; - const loopPol = agg_policy[f]?.[4] || 1; - - if (seqPol === 1 || loopPol === 1) { // SUM - // For SUM: upper bound = max_value * number_of_tasks * reasonable_loop_factor - // Use a tight bound to avoid Gecode overflow - const sumBound = maxVal * Math.max(n_tasks, 1) * 100; - qos_ub.push(sumBound); - } else if (seqPol === 2 || loopPol === 2) { // PROD - // If values > 1, grows fast. If <= 1, stays <= 1. - // Assume normalized 0-1 for reliability if product used. - if (maxVal <= 1.0) qos_ub.push(1.0); - else qos_ub.push(Math.pow(maxVal, Math.min(n_tasks, 10))); - } else { - // MAX/MIN - bound is just the max candidate value with margin - qos_ub.push(maxVal * 2); + // SEQ, AND (FLOW) usually SUM or MAX or PRODUCT + if (fn === 'SUM' || fn === 'SCALED_SUM') { + return childVals.reduce((a, b) => a + b, 0); } - } - - // --- 4. Flatten Tree --- - const nodes: any[] = []; - const traverse = (node: any): number => { - const myIdx = nodes.length + 1; - - // LOOP iterations: support both 'iterations' and 'expected_iterations' - let loopIters = 0.0; - if (node.kind === 'LOOP') { - loopIters = node.iterations || node.expected_iterations || 1.0; + if (fn === 'PRODUCT' || fn === 'SCALED_PRODUCT') { + return childVals.reduce((a, b) => a * b, 1); } - - const nodeEntry = { - kind: this.getKind(node.kind), - task_id: node.kind === 'TASK' ? taskIdx[node.task_id] : 0, - children: [] as number[], - xor_probs: [] as number[], - loop_iters: loopIters - }; - nodes.push(nodeEntry); - - if (node.children) { - // For XOR nodes, children may have 'probability' property - const isXOR = node.kind === 'XOR'; - for (const child of node.children) { - const childIdx = traverse(child); - nodeEntry.children.push(childIdx); - // Extract probability for XOR children - nodeEntry.xor_probs.push(isXOR ? (child.probability || 0.0) : 0.0); - } - } else if (node.branches) { // XOR with branches format - for (const br of node.branches) { - const childIdx = traverse(br.child); - nodeEntry.children.push(childIdx); - nodeEntry.xor_probs.push(br.p || 0.0); - } - } else if (node.body) { // LOOP: body is single child - const childIdx = traverse(node.body); - nodeEntry.children.push(childIdx); - nodeEntry.xor_probs.push(0.0); + if (fn === 'MAX') { + return Math.max(...childVals); + } + if (fn === 'MIN') { + return Math.min(...childVals); } - return myIdx; - }; - - const root = instance.composition.root; - let root_id = 1; - if (root) root_id = traverse(root); - - const n_nodes = nodes.length; - const max_children = Math.max(1, ...nodes.map(n => n.children.length)); - const pad = (arr: number[], len: number, val: number) => [...arr, ...Array(Math.max(0, len - arr.length)).fill(val)]; - const node_kind = nodes.map(n => n.kind); - const node_task_id = nodes.map(n => n.task_id); - const node_n_children = nodes.map(n => n.children.length); - const node_children = nodes.map(n => pad(n.children, max_children, 0)); - const node_xor_probs = nodes.map(n => pad(n.xor_probs, max_children, 0.0)); - const node_loop_iters = nodes.map(n => n.loop_iters); + // Default fallback + return childVals.reduce((a, b) => a + b, 0); + }; - // --- 5. Weights --- - const obj = instance.objective || {}; - const weightsObj = obj.weights || {}; - const qos_weights: number[] = []; - for (const feat of features) { - qos_weights.push(Number(weightsObj[feat] || 0.0)); + const result: Record = {}; + const root = instance.composition?.root; + if (root) { + features.forEach(featId => { + result[featId] = traverse(root, featId); + }); } + return result; + } private validateBestPractices(instance: any): Array> { + const violations: Array> = []; + const tasks = Array.isArray(instance.tasks) ? instance.tasks : []; + const definedTaskIds = new Set( + tasks + .map((t: any) => t.id) + .filter((id: unknown): id is string => typeof id === 'string') + ); + const usedTaskIds = new Set(); - // --- 6. Constraints --- - const constraints = instance.constraints || []; - const opMap: Record = { "<=": 1, ">=": 2, "==": 3, "<": 4, ">": 5 }; - - const gc_attr: number[] = []; - const gc_op: number[] = []; - const gc_val: number[] = []; - - const lc_task: number[] = []; - const lc_attr: number[] = []; - const lc_op: number[] = []; - const lc_val: number[] = []; - - const dc_type: number[] = []; - const dc_t1: number[] = []; - const dc_t2: number[] = []; - - for (const c of constraints) { - // Skip soft constraints for now - if (c.hard === false) continue; - - if (c.kind === 'attribute_bound') { - const attrIdx = featureMap[c.attribute_id]; - const op = opMap[c.op]; - if (!attrIdx || !op) continue; - - if (c.scope === 'global') { - gc_attr.push(attrIdx); - gc_op.push(op); - gc_val.push(c.value); - } else if (c.scope === 'local' && c.task_id) { - const tIdx = taskIdx[c.task_id]; - if (tIdx) { - lc_task.push(tIdx); - lc_attr.push(attrIdx); - lc_op.push(op); - lc_val.push(c.value); - } - } - } else if (c.kind === 'dependency') { - // ... (Same as before) - const tIndices = (c.tasks || []).map((tid: string) => taskIdx[tid]).filter((i: any) => i); - if (tIndices.length < 2) continue; - - if (c.type === 'same_provider') { - for (let i = 0; i < tIndices.length - 1; i++) { - dc_type.push(1); - dc_t1.push(tIndices[i]); - dc_t2.push(tIndices[i + 1]); - } - } else if (c.type === 'different_provider') { - for (let i = 0; i < tIndices.length; i++) { - for (let j = i + 1; j < tIndices.length; j++) { - dc_type.push(2); - dc_t1.push(tIndices[i]); - dc_t2.push(tIndices[j]); - } - } - } + const traverse = (node: any): void => { + if (!node) { + return; } - } - return ` - root_id = ${root_id}; - PROB_EPS = 1e-6; - - n_tasks = ${n_tasks}; - n_candidates = ${n_candidates}; - n_nodes = ${n_nodes}; - n_qos = ${n_qos}; - max_children = ${max_children}; - - max_cands_per_task = ${max_cands_per_task}; - n_task_cands = ${fmt(n_task_cands)}; - task_cands = ${fmt2d(task_cands)}; - - cand_qos = ${fmt2d(cand_qos)}; - candidate_provider = ${fmt(cand_provider)}; - - node_kind = ${fmt(node_kind)}; - node_task_id = ${fmt(node_task_id)}; - node_n_children = ${fmt(node_n_children)}; - node_children = ${fmt2d(node_children)}; - node_xor_probs = ${fmt2d(node_xor_probs)}; - node_loop_iters = ${fmt(node_loop_iters)}; - - agg_policy = ${fmt2d(agg_policy)}; - - qos_weights = ${fmt(qos_weights)}; - qos_ub = ${fmt(qos_ub)}; - - n_global_constraints = ${gc_attr.length}; - gc_attr = ${fmt(gc_attr)}; - gc_op = ${fmt(gc_op)}; - gc_val = ${fmt(gc_val)}; - - n_local_constraints = ${lc_task.length}; - lc_task = ${fmt(lc_task)}; - lc_attr = ${fmt(lc_attr)}; - lc_op = ${fmt(lc_op)}; - lc_val = ${fmt(lc_val)}; - - n_dep_constraints = ${dc_type.length}; - dc_type = ${fmt(dc_type)}; - dc_t1 = ${fmt(dc_t1)}; - dc_t2 = ${fmt(dc_t2)}; - `; - } - - private getKind(k: string): number { - if (k === 'TASK') return 1; - if (k === 'SEQ') return 2; - if (k === 'AND') return 3; - if (k === 'XOR') return 4; - if (k === 'LOOP') return 5; - return 0; - } - - private mapTasks(instance: any): Record { - const map: Record = {}; - instance.tasks.forEach((t: any, i: number) => map[i + 1] = t.id); - return map; - } - - private validateBestPractices(instance: any): any[] { - const violations: any[] = []; - - // 1. Disconnected Tasks (Tasks defined but not in composition) - const definedTaskIds = new Set((instance.tasks || []).map((t: any) => t.id)); - const usedTaskIds = new Set(); - - // Recursive traversal to find used tasks - const traverse = (node: any) => { - if (!node) return; if (node.kind === 'TASK' && node.task_id) { usedTaskIds.add(node.task_id); } - if (node.children) { - node.children.forEach(traverse); + + if (Array.isArray(node.children)) { + node.children.forEach((child: any) => traverse(child)); } - if (node.branches) { - node.branches.forEach((b: any) => traverse(b.child)); + + if (Array.isArray(node.branches)) { + node.branches.forEach((branch: any) => traverse(branch?.child)); } + if (node.body) { traverse(node.body); } @@ -566,29 +305,25 @@ export class Solver { traverse(instance.composition.root); } - definedTaskIds.forEach(tid => { + definedTaskIds.forEach((tid) => { if (!usedTaskIds.has(tid)) { - violations.push({ // ValidateViolation structure + violations.push({ message: `Task '${tid}' is defined but not used in the composition.`, - code: "unused_task_warning", - constraint_id: null + code: 'unused_task_warning', + constraint_id: null, }); } }); - // 2. Unweighted Objectives (Heuristic) - // If objective is weighted_sum, check if any weight is 0 (useless?) - // Actually 0 weight is fine (ignoring feature). - // But if ALL weights are 0, optimizer does nothing. const obj = instance.objective || {}; if (obj.type === 'weighted_sum' && obj.weights) { const weights = Object.values(obj.weights).map((w: any) => Number(w)); const sum = weights.reduce((a, b) => a + Math.abs(b), 0); if (sum === 0 && weights.length > 0) { violations.push({ - message: "Objective has all zero weights. Optimization effectively disabled.", - code: "zero_weights_warning", - constraint_id: null + message: 'Objective has all zero weights. Optimization effectively disabled.', + code: 'zero_weights_warning', + constraint_id: null, }); } } @@ -596,6 +331,21 @@ export class Solver { return violations; } + private mapTasks(instance: any): Record { + const map: Record = {}; + if (!Array.isArray(instance.tasks)) { + return map; + } + + instance.tasks.forEach((t: any, i: number) => { + if (t?.id) { + map[i + 1] = t.id; + } + }); + + return map; + } + private mapCandidates(instance: any): Record { const map: Record = {}; instance.candidates.forEach((c: any, i: number) => { diff --git a/engines/random-search/.settings/org.eclipse.core.resources.prefs b/engines/random-search/.settings/org.eclipse.core.resources.prefs index 3622a30..6377efd 100644 --- a/engines/random-search/.settings/org.eclipse.core.resources.prefs +++ b/engines/random-search/.settings/org.eclipse.core.resources.prefs @@ -1,3 +1,4 @@ eclipse.preferences.version=1 encoding//src/main/java=ISO-8859-1 +encoding//src/test/java=ISO-8859-1 encoding/=ISO-8859-1 diff --git a/engines/random-search/Dockerfile b/engines/random-search/Dockerfile index 50611f6..d025bf2 100644 --- a/engines/random-search/Dockerfile +++ b/engines/random-search/Dockerfile @@ -8,7 +8,7 @@ RUN mvn package -DskipTests FROM eclipse-temurin:8-jre WORKDIR /app RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/* -COPY --from=builder /app/target/ManyObjectivesQoSawareCWSBinding-0.0.1-SNAPSHOT.jar app.jar +COPY --from=builder /app/target/RandomSearchQoSawareCWSBinding-0.0.1-SNAPSHOT.jar app.jar COPY --from=builder /app/target/dependency /app/dependency EXPOSE 8080 CMD ["java", "-cp", "app.jar:dependency/*", "es.us.isa.qosawarewsbinding.api.Server"] diff --git a/engines/random-search/pom.xml b/engines/random-search/pom.xml index e8233bc..f3f5d56 100644 --- a/engines/random-search/pom.xml +++ b/engines/random-search/pom.xml @@ -1,7 +1,7 @@ 4.0.0 es.us.isa - ManyObjectivesQoSawareCWSBinding + RandomSearchQoSawareCWSBinding 0.0.1-SNAPSHOT ISO-8859-1 @@ -17,6 +17,12 @@ gson 2.8.9 + + junit + junit + 4.12 + test + diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/AbstractWebService.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/AbstractWebService.java index 0492e02..e7cc175 100644 --- a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/AbstractWebService.java +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/AbstractWebService.java @@ -33,4 +33,28 @@ public boolean isEmpty() { return false; } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AbstractWebService other = (AbstractWebService) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } } diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/EmptyComponent.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/EmptyComponent.java new file mode 100644 index 0000000..3993d07 --- /dev/null +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/EmptyComponent.java @@ -0,0 +1,31 @@ +package es.us.isa.qosawarewsbinding; + +import java.io.Serializable; + +/** + * A no-op structural component representing an "ELEMENT" node in the + * composition. + * It is used for branches that do nothing (e.g., "skip" branches). + */ +public class EmptyComponent implements StructuralComponent, Serializable { + + private String id; + + public EmptyComponent(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + @Override + public String toStructuralString(String prefix) { + return prefix + "ELEMENT(" + id + ")"; + } + + @Override + public boolean isEmpty() { + return false; + } +} diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/WSCompositionStructure.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/WSCompositionStructure.java index 230e21b..f0877c4 100644 --- a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/WSCompositionStructure.java +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/WSCompositionStructure.java @@ -57,7 +57,9 @@ private int NBuildingBlocks(Class aClass, StructuralComponent structure) { private void addComponent(StructuralComponent structure) { if(structure instanceof AbstractWebService) components.add((AbstractWebService) structure); - else{ + else if (structure instanceof EmptyComponent) { + // Do nothing, no AbstractWebService here + } else if (structure instanceof CompositeStructuralComponent) { Collection subcomponents=((CompositeStructuralComponent)structure).getSubComponents(); for(StructuralComponent subcomponent:subcomponents) addComponent(subcomponent); @@ -166,6 +168,8 @@ private double numberOfExecutedTasks(StructuralComponent structure) { else result+=numberOfExecutedTasks(subComponent)*compositeComponent.getPonderation(subComponent); } + } else if (structure instanceof EmptyComponent) { + result = 0; }else result=1; return result; diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/Controller.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/Controller.java index c101f6f..aa2df32 100644 --- a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/Controller.java +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/Controller.java @@ -5,28 +5,25 @@ import com.sun.net.httpserver.HttpHandler; import es.us.isa.qosawarewsbinding.AbstractWebService; import es.us.isa.qosawarewsbinding.ConcreteWebService; -import es.us.isa.qosawarewsbinding.StructuralComponent; -import es.us.isa.qosawarewsbinding.WSCompositionStructure; import es.us.isa.qosawarewsbinding.api.dto.SolveRequest; import es.us.isa.qosawarewsbinding.api.dto.SolveResponse; +import es.us.isa.qosawarewsbinding.api.mapping.ProblemBuildResult; +import es.us.isa.qosawarewsbinding.api.mapping.ProblemBuilder; +import es.us.isa.qosawarewsbinding.api.solver.RandomSearchSolver; import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; -import es.us.isa.qosawarewsbinding.problem.WSCompositionQoSModel; -import es.us.isa.qosawarewsbinding.problem.GlobalQoSWSCompositionConstraint; -import es.us.isa.qosawarewsbinding.problem.BinaryOperator; import es.us.isa.qosawarewsbinding.qos.QoSProperty; -import es.us.isa.qosawarewsbinding.qos.QoSPropertyType; -import es.us.isa.qosawarewsbinding.qos.aggretation.*; import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; -import es.us.isa.qosawarewsbinding.solution.vector.*; -import es.us.isa.qosawarewsbinding.*; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; -import java.util.*; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; public class Controller implements HttpHandler { - private Gson gson = new Gson(); + private final Gson gson = new Gson(); @Override public void handle(HttpExchange exchange) throws IOException { @@ -45,9 +42,19 @@ public void handle(HttpExchange exchange) throws IOException { OutputStream os = exchange.getResponseBody(); os.write(jsonResp.getBytes()); os.close(); - } catch (Exception e) { - e.printStackTrace(); + } catch (IllegalArgumentException e) { String error = "{\"error\": \"" + e.getMessage() + "\"}"; + exchange.sendResponseHeaders(422, error.length()); + OutputStream os = exchange.getResponseBody(); + os.write(error.getBytes()); + os.close(); + } catch (Exception e) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + String stackTrace = sw.toString().replace("\"", "'").replace("\n", "\\n"); + + String error = "{\"error\": \"" + e.getMessage() + "\", \"stack\": \"" + stackTrace + "\"}"; exchange.sendResponseHeaders(500, error.length()); OutputStream os = exchange.getResponseBody(); os.write(error.getBytes()); @@ -56,180 +63,38 @@ public void handle(HttpExchange exchange) throws IOException { } private SolveResponse process(SolveRequest req) { - // 1. Map Structure - Map taskMap = new HashMap(); - StructuralComponent root = mapNode(req.composition.root, taskMap); - WSCompositionStructure structure = new WSCompositionStructure(root); - - // 2. Map QoS Model - Map> propertyMap = new HashMap>(); - Set qosProperties = new HashSet(); - - for (Map.Entry entry : req.features.properties.entrySet()) { - QoSPropertyType type = "maximize".equals(entry.getValue().direction) ? QoSPropertyType.POSITIVE - : QoSPropertyType.NEGATIVE; - // Assuming 0.0-1.0 domain for normalization - QoSProperty prop = new QoSProperty(entry.getKey(), - new es.us.isa.qosawarewsbinding.util.BoundedDomain(0.0, 1.0), type); - qosProperties.add(prop); - propertyMap.put(entry.getKey(), prop); - } - WSCompositionQoSModel qosModel = new WSCompositionQoSModel(qosProperties); - - // Map weights - Map weights = new HashMap(); - for (Map.Entry entry : req.features.weights.entrySet()) { - weights.put(propertyMap.get(entry.getKey()), entry.getValue()); - } - qosModel.setQosPropertiesWeights(weights); - - // Map aggregation functions - for (Map.Entry entry : req.features.aggregation.entrySet()) { - QoSProperty prop = propertyMap.get(entry.getKey()); - SolveRequest.AggregationPolicy policy = entry.getValue(); - - qosModel.setAggregationFunction(prop, Sequence.class, getAggFunc(policy.seq)); - qosModel.setAggregationFunction(prop, Flow.class, getAggFunc(policy.flow)); - qosModel.setAggregationFunction(prop, Branch.class, getAggFunc(policy.branch)); - qosModel.setAggregationFunction(prop, Loop.class, getAggFunc(policy.loop)); - } - - // 3. Map Market - Map> market = new HashMap>(); - // Need to find all AbstractWebServices (Tasks) in structure + ProblemBuilder builder = new ProblemBuilder(); + ProblemBuildResult mapped = builder.build(req); + QoSAwareWSCompositionProblem problem = mapped.problem; - // collectTasks called during mapping - - for (Map.Entry entry : taskMap.entrySet()) { - String taskId = entry.getKey(); - AbstractWebService aws = entry.getValue(); - Set candidates = new HashSet(); - - SolveRequest.ServiceCandidates sc = req.market.get(taskId); - if (sc != null && sc.services != null) { - for (SolveRequest.Service s : sc.services) { - ConcreteWebService cws = new ConcreteWebService(s.id, aws); - - // Iterate over all expected properties to ensure completeness - for (QoSProperty p : propertyMap.values()) { - Double val = s.features.get(p.getName()); - if (val == null) { - // Assign default based on type - if (p.getType() == QoSPropertyType.POSITIVE) { - val = 0.0; - } else { - // For minimization, we'd ideally want a "bad" value. - // But Double.MAX_VALUE might skew normalization too much. - // Let's use a reasonably high value or 0 if that's safer for now, - // but for robustness, 999999.0 is a placeholder "bad" value. - val = 999999.0; - } - System.err.println("Warning: Missing QoS value for " + p.getName() + " in service " + s.id - + " (Task " + taskId + "). Using default: " + val); - } - cws.setQoSValue(p, val); - } - candidates.add(cws); - } - } - market.put(aws, candidates); - } - - // 4. Create Problem (constraints will be attached after instantiation) - QoSAwareWSCompositionProblem problem = new QoSAwareWSCompositionProblem( - structure, - market, - qosModel, - new LinkedList() - ); - - // 4.1 Map Global Attribute Bound Constraints (if any) - if (req.constraints != null) { - for (SolveRequest.Constraint c : req.constraints) { - if (c == null) { - continue; - } - if (c.kind == null || !"attribute_bound".equalsIgnoreCase(c.kind)) { - continue; - } - if (c.scope != null && !"global".equalsIgnoreCase(c.scope)) { - continue; - } - if (c.attribute_id == null || c.op == null || c.value == null) { - continue; - } - - QoSProperty prop = propertyMap.get(c.attribute_id); - if (prop == null) { - continue; - } - - BinaryOperator op; - if ("==".equals(c.op)) { - op = BinaryOperator.EQUAL; - } else if ("!=".equals(c.op)) { - op = BinaryOperator.DISTINCT; - } else if (">".equals(c.op)) { - op = BinaryOperator.GREATER; - } else if (">=".equals(c.op)) { - op = BinaryOperator.GREATEREQUAL; - } else if ("<".equals(c.op)) { - op = BinaryOperator.LOWER; - } else if ("<=".equals(c.op)) { - op = BinaryOperator.LOWEREQUAL; - } else { - continue; - } - - problem.getConstraints().add(new GlobalQoSWSCompositionConstraint(problem, prop, c.value, op)); - } - } - - // 5. Solve (Simple Random Search) int iterations = 1000; if (req.config != null && req.config.max_iterations > 0) { iterations = req.config.max_iterations; } long start = System.currentTimeMillis(); - QoSAwareWSCompositionSolution bestSol = solveSimple(problem, iterations); + RandomSearchSolver solver = new RandomSearchSolver(); + QoSAwareWSCompositionSolution bestSol = solver.solve(problem, iterations); long end = System.currentTimeMillis(); - // 6. Map Response + if (problem.feasibilityDistance(bestSol) > 0) { + throw new IllegalArgumentException( + "No feasible solution found after " + iterations + " iterations."); + } + SolveResponse resp = new SolveResponse(); resp.execution_time = end - start; - resp.iterations_count = iterations; // Report actual iterations used + resp.iterations_count = iterations; resp.status = "optimized"; resp.selection = new HashMap(); resp.aggregated_features = new HashMap(); - // Populate selection - if (bestSol instanceof QoSAwareWSCompositionVectorSolution) { - QoSAwareWSCompositionVectorSolution vecSol = (QoSAwareWSCompositionVectorSolution) bestSol; - // Need to map back AWS -> CWS ID - // The Solution interface doesn't expose map easily, but VectorSolution does - // Actually VectorSolution stores selection in a Map - // But it is protected or invalid access? - // Let's assume we can get it or we need a way. - // VectorSolution has getSelectedService(AbstractWebService) ?? - // Checking source... it extends AbstractSolution. - } - - // Workaround: We need to modify QoSAwareWSCompositionVectorSolution or inspect - // it. - // It has getService(AbstractWebService) ? - // I will check AbstractSolution source code if I can. - // For now, assume a method to extract selection. - - // Evaluate QoS - for (QoSProperty p : propertyMap.values()) { - double val = qosModel.evaluate(bestSol, p, structure); + for (QoSProperty p : mapped.propertyMap.values()) { + double val = mapped.qosModel.evaluate(bestSol, p, mapped.structure); resp.aggregated_features.put(p.getName(), val); } - // Populate selection map - for (Map.Entry entry : taskMap.entrySet()) { + for (Map.Entry entry : mapped.taskMap.entrySet()) { String taskId = entry.getKey(); AbstractWebService aws = entry.getValue(); ConcreteWebService cws = bestSol.getSelectedService(aws); @@ -241,119 +106,4 @@ private SolveResponse process(SolveRequest req) { return resp; } - private AggregationFunction getAggFunc(String name) { - if ("sum".equalsIgnoreCase(name)) - return SumatoryAggregationFunction.getInstance(); - if ("product".equalsIgnoreCase(name)) - return ProductoryAggregationFunction.getInstance(); - if ("max".equalsIgnoreCase(name)) - return MaxAggregationFunction.getInstance(); - if ("min".equalsIgnoreCase(name)) - return MinAggregationFunction.getInstance(); - return SumatoryAggregationFunction.getInstance(); // default - } - - private void collectTasks(StructuralComponent node, Map map) { - if (node instanceof AbstractWebService) { - // How do we know the ID? We constructed it with ID. - // AbstractWebService(String id). - // But AbstractWebService constructor takes 'id'. - // I need to store the mapping. - // Actually I should store mapping when creating node. - // AbstractWebService does not expose ID easily? It inherits from - // StructuralComponent ?? - // StructuralComponent doesn't seem to have ID accessor? - // Checking source needed. - // Assuming toString() or similar return ID, or I map objects. - // Best way: Map in context? - } - if (node instanceof CompositeStructuralComponent) { - for (StructuralComponent child : ((CompositeStructuralComponent) node).getSubComponents()) { - collectTasks(child, map); - } - } - } - - private StructuralComponent mapNode(SolveRequest.Node node, Map taskMap) { - if (node == null) { - return null; - } - if ("TASK".equals(node.kind)) { - AbstractWebService aws = new AbstractWebService(node.task_id); - taskMap.put(node.task_id, aws); - return aws; - } else if ("SEQ".equals(node.kind)) { - Sequence seq = new Sequence(); - if (node.children != null) { - for (SolveRequest.Node child : node.children) { - StructuralComponent sc = mapNode(child, taskMap); - if (sc != null) { - seq.getSubComponents().add(sc); - } - } - } - return seq; - } else if ("AND".equals(node.kind)) { - Flow flow = new Flow(); - if (node.children != null) { - for (SolveRequest.Node child : node.children) { - StructuralComponent sc = mapNode(child, taskMap); - if (sc != null) { - flow.getSubComponents().add(sc); - } - } - } - return flow; - } else if ("XOR".equals(node.kind)) { - Branch branch = new Branch(); - if (node.branches != null) { - for (SolveRequest.Branch b : node.branches) { - StructuralComponent child = mapNode(b.child, taskMap); - if (child != null) { - branch.addBranch(child, b.p); - } - } - } - return branch; - } else if ("LOOP".equals(node.kind)) { - int iterations = 1; - if (node.expected_iterations != null) { - iterations = (int) Math.round(node.expected_iterations.doubleValue()); - if (iterations < 0) { - iterations = 0; - } - } - Loop loop = new Loop(iterations); - if (node.body != null) { - StructuralComponent body = mapNode(node.body, taskMap); - if (body != null) { - loop.getSubComponents().add(body); - } - } - return loop; - } - return null; - } - - private QoSAwareWSCompositionSolution solveSimple(QoSAwareWSCompositionProblem problem, int iterations) { - // Simple Random Search - // Initialize with default (all 0 index) or random - QoSAwareWSCompositionSolution best = new QoSAwareWSCompositionVectorSolution(problem); - // best = best.createRandom(); // Maybe start random? - double bestFitness = problem.fitness(best); - - for (int i = 0; i < iterations; i++) { - // Create a new random solution - QoSAwareWSCompositionSolution sol = (QoSAwareWSCompositionSolution) new QoSAwareWSCompositionVectorSolution( - problem).createRandom(); - - double f = problem.fitness(sol); - - if (f < bestFitness) { - best = sol; - bestFitness = f; - } - } - return best; - } } diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/Server.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/Server.java index 9af0bd1..336cbfd 100644 --- a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/Server.java +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/Server.java @@ -23,7 +23,6 @@ public void handle(HttpExchange exchange) throws IOException { }); server.createContext("/solve", new Controller()); server.setExecutor(Executors.newCachedThreadPool()); - System.out.println("Many-OBJ Service started on port " + port); server.start(); } } diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/dto/SolveRequest.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/dto/SolveRequest.java index d6ef63d..b1415c7 100644 --- a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/dto/SolveRequest.java +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/dto/SolveRequest.java @@ -38,6 +38,7 @@ public static class ServiceCandidates { public static class Service { public String id; // service concrete ID (e.g. "s11") public String name; + public String provider_id; // provider identity for DEPENDENCY constraints public Map features; } @@ -49,6 +50,8 @@ public static class QoSModel { public static class QoSPropertyDef { public String direction; // "minimize", "maximize" + public Double min; + public Double max; } public static class AggregationPolicy { @@ -61,16 +64,19 @@ public static class AggregationPolicy { public static class SolvingConfig { public int max_iterations; - public int population_size; } public static class Constraint { public String id; - public String kind; // "attribute_bound" - public String scope; // "global" + public String kind; // "attribute_bound", "range_global", "dependency", "local_attribute_bound" + public String scope; // "global", "local" public String attribute_id; - public String op; // <=, <, >=, >, ==, != + public String op; // <=, <, >=, >, ==, !=, IN_RANGE public Double value; + public Double min; // For IN_RANGE + public Double max; // For IN_RANGE + public java.util.List tasks; // For LOCAL and DEPENDENCY + public String type; // For DEPENDENCY (SAME_PROVIDER, DIFFERENT_PROVIDER) public Boolean hard; } } diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/mapping/ProblemBuildResult.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/mapping/ProblemBuildResult.java new file mode 100644 index 0000000..9e9ffd8 --- /dev/null +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/mapping/ProblemBuildResult.java @@ -0,0 +1,36 @@ +package es.us.isa.qosawarewsbinding.api.mapping; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.WSCompositionStructure; +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.problem.WSCompositionQoSModel; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; + +import java.util.Map; +import java.util.Set; + +public class ProblemBuildResult { + public final QoSAwareWSCompositionProblem problem; + public final WSCompositionStructure structure; + public final WSCompositionQoSModel qosModel; + public final Map taskMap; + public final Map> propertyMap; + public final Map> market; + + public ProblemBuildResult( + QoSAwareWSCompositionProblem problem, + WSCompositionStructure structure, + WSCompositionQoSModel qosModel, + Map taskMap, + Map> propertyMap, + Map> market + ) { + this.problem = problem; + this.structure = structure; + this.qosModel = qosModel; + this.taskMap = taskMap; + this.propertyMap = propertyMap; + this.market = market; + } +} diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/mapping/ProblemBuilder.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/mapping/ProblemBuilder.java new file mode 100644 index 0000000..37f90f6 --- /dev/null +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/mapping/ProblemBuilder.java @@ -0,0 +1,296 @@ +package es.us.isa.qosawarewsbinding.api.mapping; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.Branch; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.EmptyComponent; +import es.us.isa.qosawarewsbinding.Flow; +import es.us.isa.qosawarewsbinding.Loop; +import es.us.isa.qosawarewsbinding.Sequence; +import es.us.isa.qosawarewsbinding.StructuralComponent; +import es.us.isa.qosawarewsbinding.WSCompositionStructure; +import es.us.isa.qosawarewsbinding.api.dto.SolveRequest; +import es.us.isa.qosawarewsbinding.problem.BinaryOperator; +import es.us.isa.qosawarewsbinding.problem.GlobalQoSWSCompositionConstraint; +import es.us.isa.qosawarewsbinding.problem.LocalQoSWSCompositionConstraint; +import es.us.isa.qosawarewsbinding.problem.ProviderRelationWSCompositionConstraint; +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.problem.RangeGlobalQoSWSCompositionConstraint; +import es.us.isa.qosawarewsbinding.problem.SimpleUnfeasibilityPenalizator; +import es.us.isa.qosawarewsbinding.problem.WSCompositionQoSModel; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.qos.QoSPropertyType; +import es.us.isa.qosawarewsbinding.qos.aggretation.AggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.MaxAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.MinAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.ScaledSumAggregationFunction; +import es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryAggregationFunction; +import es.us.isa.qosawarewsbinding.util.BoundedDomain; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class ProblemBuilder { + public ProblemBuildResult build(SolveRequest req) { + Map taskMap = new HashMap(); + Map serviceProviderMap = new HashMap(); + + StructuralComponent root = mapNode(req.composition.root, taskMap); + WSCompositionStructure structure = new WSCompositionStructure(root); + + Map> propertyMap = new HashMap>(); + Set qosProperties = new HashSet(); + + for (Map.Entry entry : req.features.properties.entrySet()) { + QoSPropertyType type = "maximize".equals(entry.getValue().direction) + ? QoSPropertyType.POSITIVE + : QoSPropertyType.NEGATIVE; + + Double min = entry.getValue().min != null ? entry.getValue().min : 0.0; + Double max = entry.getValue().max != null ? entry.getValue().max : 1.0; + + QoSProperty prop = new QoSProperty( + entry.getKey(), + new BoundedDomain(min, max), + type + ); + qosProperties.add(prop); + propertyMap.put(entry.getKey(), prop); + } + WSCompositionQoSModel qosModel = new WSCompositionQoSModel(qosProperties); + + Map weights = new HashMap(); + for (Map.Entry entry : req.features.weights.entrySet()) { + QoSProperty prop = propertyMap.get(entry.getKey()); + if (prop != null) { + weights.put(prop, entry.getValue()); + } + } + qosModel.setQosPropertiesWeights(weights); + + for (Map.Entry entry : req.features.aggregation.entrySet()) { + QoSProperty prop = propertyMap.get(entry.getKey()); + SolveRequest.AggregationPolicy policy = entry.getValue(); + + qosModel.setAggregationFunction(prop, Sequence.class, getAggFunc(policy.seq)); + qosModel.setAggregationFunction(prop, Flow.class, getAggFunc(policy.flow)); + qosModel.setAggregationFunction(prop, Branch.class, getAggFunc(policy.branch)); + qosModel.setAggregationFunction(prop, Loop.class, getAggFunc(policy.loop)); + } + + Map> market = new HashMap>(); + for (Map.Entry entry : taskMap.entrySet()) { + String taskId = entry.getKey(); + AbstractWebService aws = entry.getValue(); + Set candidates = new HashSet(); + + SolveRequest.ServiceCandidates sc = req.market.get(taskId); + if (sc != null && sc.services != null) { + for (SolveRequest.Service s : sc.services) { + ConcreteWebService cws = new ConcreteWebService(s.id, aws); + + if (s.provider_id != null) { + serviceProviderMap.put(s.id, s.provider_id); + } + + for (QoSProperty p : propertyMap.values()) { + Double val = s.features.get(p.getName()); + if (val == null) { + if (p.getType() == QoSPropertyType.POSITIVE) { + val = 0.0; + } else { + val = 999999.0; + } + } + cws.setQoSValue(p, val); + } + candidates.add(cws); + } + } + market.put(aws, candidates); + } + + QoSAwareWSCompositionProblem problem = new QoSAwareWSCompositionProblem( + structure, + market, + qosModel, + new LinkedList() + ); + problem.setPenalizator(new SimpleUnfeasibilityPenalizator()); + + applyConstraints(req, problem, taskMap, propertyMap, serviceProviderMap); + + return new ProblemBuildResult(problem, structure, qosModel, taskMap, propertyMap, market); + } + + private void applyConstraints( + SolveRequest req, + QoSAwareWSCompositionProblem problem, + Map taskMap, + Map> propertyMap, + Map serviceProviderMap + ) { + if (req.constraints == null) { + return; + } + + for (SolveRequest.Constraint c : req.constraints) { + boolean hard = c.hard != null ? c.hard : true; + + if ("dependency".equalsIgnoreCase(c.kind)) { + List relatedTasks = new ArrayList(); + if (c.tasks != null) { + for (String tid : c.tasks) { + AbstractWebService t = taskMap.get(tid); + if (t != null) { + relatedTasks.add(t); + } + } + } + ProviderRelationWSCompositionConstraint.Type type = + "SAME_PROVIDER".equalsIgnoreCase(c.type) + ? ProviderRelationWSCompositionConstraint.Type.SAME_PROVIDER + : ProviderRelationWSCompositionConstraint.Type.DIFFERENT_PROVIDER; + + ProviderRelationWSCompositionConstraint depConstraint = new ProviderRelationWSCompositionConstraint( + problem, type, relatedTasks, hard); + depConstraint.setServiceProviderMap(serviceProviderMap); + problem.getConstraints().add(depConstraint); + continue; + } + + if ("attribute_bound".equalsIgnoreCase(c.kind)) { + QoSProperty prop = propertyMap.get(c.attribute_id); + if (prop == null) { + continue; + } + + BinaryOperator op = getOperator(c.op); + + if (BinaryOperator.IN_RANGE.equals(op)) { + problem.getConstraints() + .add(new RangeGlobalQoSWSCompositionConstraint(problem, prop, c.min, c.max, hard)); + continue; + } + + if ("local".equalsIgnoreCase(c.scope)) { + if (c.tasks != null) { + for (String tid : c.tasks) { + AbstractWebService t = taskMap.get(tid); + if (t != null) { + problem.getConstraints().add( + new LocalQoSWSCompositionConstraint(problem, prop, op, c.value, t, hard)); + } + } + } + } else { + GlobalQoSWSCompositionConstraint gc = new GlobalQoSWSCompositionConstraint(problem, prop, + c.value, op); + gc.setHard(hard); + problem.getConstraints().add(gc); + } + } + } + } + + private AggregationFunction getAggFunc(String name) { + if ("sum".equalsIgnoreCase(name)) + return SumatoryAggregationFunction.getInstance(); + if ("product".equalsIgnoreCase(name)) + return ProductoryAggregationFunction.getInstance(); + if ("max".equalsIgnoreCase(name)) + return MaxAggregationFunction.getInstance(); + if ("min".equalsIgnoreCase(name)) + return MinAggregationFunction.getInstance(); + if ("scaled_sum".equalsIgnoreCase(name)) + return ScaledSumAggregationFunction.getInstance(); + return SumatoryAggregationFunction.getInstance(); + } + + private StructuralComponent mapNode(SolveRequest.Node node, Map taskMap) { + if (node == null) { + return null; + } + if ("TASK".equals(node.kind)) { + AbstractWebService aws = new AbstractWebService(node.task_id); + taskMap.put(node.task_id, aws); + return aws; + } else if ("SEQ".equals(node.kind)) { + Sequence seq = new Sequence(); + if (node.children != null) { + for (SolveRequest.Node child : node.children) { + StructuralComponent sc = mapNode(child, taskMap); + if (sc != null) { + seq.getSubComponents().add(sc); + } + } + } + return seq; + } else if ("AND".equals(node.kind)) { + Flow flow = new Flow(); + if (node.children != null) { + for (SolveRequest.Node child : node.children) { + StructuralComponent sc = mapNode(child, taskMap); + if (sc != null) { + flow.getSubComponents().add(sc); + } + } + } + return flow; + } else if ("XOR".equals(node.kind)) { + Branch branch = new Branch(); + if (node.branches != null) { + for (SolveRequest.Branch b : node.branches) { + StructuralComponent child = mapNode(b.child, taskMap); + if (child != null) { + branch.addBranch(child, b.p); + } + } + } + return branch; + } else if ("LOOP".equals(node.kind)) { + int iterations = 1; + if (node.expected_iterations != null) { + iterations = (int) Math.round(node.expected_iterations.doubleValue()); + if (iterations < 0) { + iterations = 0; + } + } + Loop loop = new Loop(iterations); + if (node.body != null) { + StructuralComponent body = mapNode(node.body, taskMap); + if (body != null) { + loop.getSubComponents().add(body); + } + } + return loop; + } else if ("ELEMENT".equals(node.kind)) { + return new EmptyComponent(node.id); + } + return null; + } + + private BinaryOperator getOperator(String op) { + if ("==".equals(op)) + return BinaryOperator.EQUAL; + if ("!=".equals(op)) + return BinaryOperator.DISTINCT; + if (">".equals(op)) + return BinaryOperator.GREATER; + if (">=".equals(op)) + return BinaryOperator.GREATEREQUAL; + if ("<".equals(op)) + return BinaryOperator.LOWER; + if ("<=".equals(op)) + return BinaryOperator.LOWEREQUAL; + if ("IN_RANGE".equals(op) || "in_range".equalsIgnoreCase(op)) + return BinaryOperator.IN_RANGE; + return BinaryOperator.EQUAL; + } +} diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/solver/RandomSearchSolver.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/solver/RandomSearchSolver.java new file mode 100644 index 0000000..3fb5fca --- /dev/null +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/api/solver/RandomSearchSolver.java @@ -0,0 +1,30 @@ +package es.us.isa.qosawarewsbinding.api.solver; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; +import es.us.isa.qosawarewsbinding.solution.vector.QoSAwareWSCompositionVectorSolution; + +import java.util.List; + +public class RandomSearchSolver { + + public QoSAwareWSCompositionSolution solve(QoSAwareWSCompositionProblem problem, int iterations) { + QoSAwareWSCompositionSolution best = new QoSAwareWSCompositionVectorSolution(problem); + double bestFitness = problem.fitness(best); + final double eps = 1e-12; + + for (int i = 0; i < iterations; i++) { + QoSAwareWSCompositionSolution sol = (QoSAwareWSCompositionSolution) + new QoSAwareWSCompositionVectorSolution(problem).createRandom(); + + double f = problem.fitness(sol); + + if (f < bestFitness - eps) { + best = sol; + bestFitness = f; + } + } + return best; + } +} diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/BinaryOperator.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/BinaryOperator.java index 4bfdf8a..59d0536 100644 --- a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/BinaryOperator.java +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/BinaryOperator.java @@ -9,4 +9,6 @@ * * @author japarejo */ -public enum BinaryOperator {EQUAL, DISTINCT(), GREATER,GREATEREQUAL,LOWER,LOWEREQUAL} +public enum BinaryOperator { + EQUAL, DISTINCT(), GREATER, GREATEREQUAL, LOWER, LOWEREQUAL, IN_RANGE +} diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/FeasibilityAwareProblem.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/FeasibilityAwareProblem.java index 047b98e..28ff538 100644 --- a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/FeasibilityAwareProblem.java +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/FeasibilityAwareProblem.java @@ -31,7 +31,7 @@ protected double computeFitness(Solution sol) { @Override protected boolean computeFeasibility(Solution sol) { - return feasibilityDistance(sol)>0; + return feasibilityDistance(sol) <= 0; } /** @@ -41,6 +41,9 @@ public UnfeasibilityPenalizator getPenalizator() { return penalizator; } + public void setPenalizator(UnfeasibilityPenalizator penalizator) { + this.penalizator = penalizator; + } } diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/LocalQoSWSCompositionConstraint.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/LocalQoSWSCompositionConstraint.java new file mode 100644 index 0000000..a687638 --- /dev/null +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/LocalQoSWSCompositionConstraint.java @@ -0,0 +1,111 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package es.us.isa.qosawarewsbinding.problem; + +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.AbstractWebService; + +import java.io.Serializable; +import java.util.List; + +/** + * + * @author antigravity + */ +public class LocalQoSWSCompositionConstraint extends WSCompositionConstraint implements Serializable { + + private QoSProperty property; + private BinaryOperator operator; + private Double value; + private AbstractWebService task; + + public LocalQoSWSCompositionConstraint(QoSAwareWSCompositionProblem problem, QoSProperty property, + BinaryOperator operator, Double value, AbstractWebService task, boolean hard) { + super(problem); + this.property = property; + this.operator = operator; + this.value = value; + this.task = task; + this.setHard(hard); + } + + @Override + public boolean meets(QoSAwareWSCompositionSolution solution) { + return meetingDistance(solution) <= 0; + } + + @Override + public double meetingDistance(QoSAwareWSCompositionSolution solution) { + es.us.isa.qosawarewsbinding.ConcreteWebService cws = solution.getSelectedService(task); + if (cws == null) + return 1.0; // Should not happen in complete solution + + Double currentVal = (Double) cws.getQoSValue(property); + if (currentVal == null) + return 1.0; // Missing data + + return meetingDistance(currentVal); + } + + private double meetingDistance(Double currentValue) { + double val = currentValue.doubleValue(); + double target = value.doubleValue(); + + // Similar logic to GlobalQoSWSCompositionConstraint + // Using existing logic for consistency + double diff = val - target; + + switch (operator) { + case EQUAL: + return Math.abs(diff); + case DISTINCT: + return (diff == 0) ? 1.0 : 0.0; + case GREATER: + return (val > target) ? 0.0 : (target - val + Double.MIN_VALUE); + case GREATEREQUAL: + return (val >= target) ? 0.0 : (target - val); + case LOWER: + return (val < target) ? 0.0 : (val - target + Double.MIN_VALUE); + case LOWEREQUAL: + return (val <= target) ? 0.0 : (val - target); + default: + return 1.0; + } + } + + public QoSProperty getProperty() { + return property; + } + + public void setProperty(QoSProperty property) { + this.property = property; + } + + public BinaryOperator getOperator() { + return operator; + } + + public void setOperator(BinaryOperator operator) { + this.operator = operator; + } + + public Double getValue() { + return value; + } + + public void setValue(Double value) { + this.value = value; + } + + public AbstractWebService getTask() { + return task; + } + + public void setTask(AbstractWebService task) { + this.task = task; + } +} diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/ProviderRelationWSCompositionConstraint.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/ProviderRelationWSCompositionConstraint.java new file mode 100644 index 0000000..68d295e --- /dev/null +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/ProviderRelationWSCompositionConstraint.java @@ -0,0 +1,97 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package es.us.isa.qosawarewsbinding.problem; + +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; +import es.us.isa.qosawarewsbinding.AbstractWebService; + +import es.us.isa.qosawarewsbinding.problem.WSCompositionConstraint; +import java.io.Serializable; +import java.util.List; +import java.util.Set; +import java.util.HashSet; +import java.util.Map; + +/** + * + * @author antigravity + */ +public class ProviderRelationWSCompositionConstraint extends WSCompositionConstraint implements Serializable { + + public enum Type { + SAME_PROVIDER, DIFFERENT_PROVIDER + } + + private Type type; + private List tasks; + private Map serviceProviderMap; // serviceId -> providerId + + public ProviderRelationWSCompositionConstraint(QoSAwareWSCompositionProblem problem, Type type, + List tasks, boolean hard) { + super(problem); + this.type = type; + this.tasks = tasks; + this.setHard(hard); + } + + public void setServiceProviderMap(Map map) { + this.serviceProviderMap = map; + } + + @Override + public boolean meets(QoSAwareWSCompositionSolution solution) { + return meetingDistance(solution) <= 0; + } + + @Override + public double meetingDistance(QoSAwareWSCompositionSolution solution) { + if (tasks == null || tasks.size() < 2) + return 0.0; + + Set providers = new HashSet(); + for (AbstractWebService task : tasks) { + es.us.isa.qosawarewsbinding.ConcreteWebService cws = solution.getSelectedService(task); + if (cws != null) { + String provider = getProvider(cws.getName()); + providers.add(provider); + } + } + + if (type == Type.SAME_PROVIDER) { + // We want 1 provider. Constraints failed by (size - 1) + return Math.max(0.0, providers.size() - 1); + } else if (type == Type.DIFFERENT_PROVIDER) { + // We want N distinct providers (where N = tasks.size()) + return Math.max(0.0, tasks.size() - providers.size()); + } + return 0.0; + } + + private String getProvider(String serviceId) { + // Use the provider map if available (populated from provider_id in the DTO) + if (serviceProviderMap != null && serviceProviderMap.containsKey(serviceId)) { + return serviceProviderMap.get(serviceId); + } + // Fallback: use service ID itself as provider identity + return serviceId; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public List getTasks() { + return tasks; + } + + public void setTasks(List tasks) { + this.tasks = tasks; + } +} diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/QoSAwareWSCompositionProblem.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/QoSAwareWSCompositionProblem.java index 87b3bce..dfdc5d2 100644 --- a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/QoSAwareWSCompositionProblem.java +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/QoSAwareWSCompositionProblem.java @@ -33,6 +33,9 @@ public class QoSAwareWSCompositionProblem extends FeasibilityAwareProblem implem private Set expaths; private static ExecutionPathsBuilder expathBuilder = null; public boolean scaled; + private Map bestCache = new HashMap(); + private Map worstCache = new HashMap(); + private Map ubCache = new HashMap(); public QoSAwareWSCompositionProblem(WSCompositionStructure structure, Map> market, WSCompositionQoSModel qosmodel, List constraints) { this.structure = structure; @@ -83,17 +86,16 @@ public String toString() { } private double scale(double value, double Qmax, double Qmin, QoSProperty property) { - double result = 0; - if (Qmax != Qmin) { - if (property.getType() == QoSPropertyType.POSITIVE) { - result = (value - Qmin) / (Qmax - Qmin); - } else { - result = (Qmax - value) / (Qmax - Qmin); - } - } else { - result = 1.0; + if (Math.abs(Qmax - Qmin) < 1e-12) { + return 0.0; } - return result; + double scaled = (value - Qmin) / (Qmax - Qmin); + if (scaled < 0.0) { + scaled = 0.0; + } else if (scaled > 1.0) { + scaled = 1.0; + } + return scaled; } private String toStringMarket() { @@ -116,28 +118,44 @@ private String toStringMarket() { public double feasibilityDistance(Solution sol) { double value = 0; for (WSCompositionConstraint constraint : getConstraints()) { - value = constraint.meetingDistance((QoSAwareWSCompositionSolution) sol); + if (constraint.isHard()) { + value += constraint.meetingDistance((QoSAwareWSCompositionSolution) sol); + } } return value; } protected double computeFitness(Solution sol) { - double feasibilityDistance = Math.min(1, feasibilityDistance(sol)); + double feasibilityDistance = feasibilityDistance(sol); double result = feasibilityFreeFitness(sol); if (getPenalizator() != null) { - result = getPenalizator().penalize(result, (1.0 - feasibilityDistance)); + result = getPenalizator().penalize(result, feasibilityDistance); } - return 1.0 - result; + return result; } public double feasibilityFreeFitness(Solution sol) { - double result = 0; if (!scaled) { scale(); } - result = getQosmodel().evaluate((QoSAwareWSCompositionSolution) sol, getStructure()); - result = result / numberOfExecutedTasks(); - return result; + double total = 0; + + for (QoSProperty property : qosmodel.getQosProperties()) { + Double agg = qosmodel.evaluate((QoSAwareWSCompositionSolution) sol, property, getStructure()); + Double weight = qosmodel.getQoSPropertyWeight(property); + + if (agg != null && weight != null) { + double ub = getQosUb(property); + double denom = ub > 1.0 ? ub : 1.0; + double signedWeight = weight; + if (property.getType() == QoSPropertyType.POSITIVE) { + signedWeight = -signedWeight; + } + total += signedWeight * (agg / denom); + } + } + + return total; } public double candidatesPerService() { @@ -169,6 +187,7 @@ public void scale() { scale(property); } scaled = true; + ubCache.clear(); //System.out.println("Problem Reescaled!! Current State:"); //System.out.println(this); } @@ -176,7 +195,20 @@ public void scale() { private void scale(QoSProperty property) { double Qmax = max(property); double Qmin = min(property); + + // Check if property has a BoundedDomain and use its bounds if available + if (property.getDomain() instanceof es.us.isa.qosawarewsbinding.util.BoundedDomain) { + es.us.isa.qosawarewsbinding.util.BoundedDomain bd = (es.us.isa.qosawarewsbinding.util.BoundedDomain) property + .getDomain(); + if (bd.getMaxBound() != null && bd.getMinBound() != null) { + Qmax = bd.getMaxBound().doubleValue(); + Qmin = bd.getMinBound().doubleValue(); + } + } + double value = 0; + boolean negative = property.getType() != QoSPropertyType.POSITIVE; + for (AbstractWebService aws : getMarket().keySet()) { for (ConcreteWebService cws : getMarket().get(aws)) { Double objVal = (Double) cws.getQoSValue(property); @@ -190,19 +222,35 @@ private void scale(QoSProperty property) { for (WSCompositionConstraint constraint : constraints) { if (constraint instanceof GlobalQoSWSCompositionConstraint) { - if (((GlobalQoSWSCompositionConstraint) constraint).getProperty().equals(property)) { - value = ((GlobalQoSWSCompositionConstraint) constraint).getValue(); + GlobalQoSWSCompositionConstraint gc = (GlobalQoSWSCompositionConstraint) constraint; + if (gc.getProperty().equals(property)) { + value = gc.getValue(); value = scale(value, Qmax, Qmin, property); - if (value < 0) { - value = 1 - value; - } - ((GlobalQoSWSCompositionConstraint) constraint).setValue(value); + gc.setValue(value); + } + } else if (constraint instanceof LocalQoSWSCompositionConstraint) { + LocalQoSWSCompositionConstraint lc = (LocalQoSWSCompositionConstraint) constraint; + if (lc.getProperty().equals(property)) { + value = lc.getValue(); + value = scale(value, Qmax, Qmin, property); + lc.setValue(value); + } + } else if (constraint instanceof RangeGlobalQoSWSCompositionConstraint) { + RangeGlobalQoSWSCompositionConstraint rc = (RangeGlobalQoSWSCompositionConstraint) constraint; + if (rc.getProperty().equals(property)) { + double minVal = rc.getMin(); + double maxVal = rc.getMax(); + rc.setMin(scale(minVal, Qmax, Qmin, property)); + rc.setMax(scale(maxVal, Qmax, Qmin, property)); } } } - + // Cache best/worst for fitness evaluation + bestCache.put(property, bestValue(property)); + worstCache.put(property, worstValue(property)); } + private double max(QoSProperty property) { double result = -Double.MAX_VALUE; boolean found = false; @@ -261,6 +309,65 @@ public double numberOfExecutedTasks() { return structure.numberOfExecutedTasks(); } + private double getQosUb(QoSProperty property) { + Double cached = ubCache.get(property); + if (cached != null) { + return cached.doubleValue(); + } + + String name = property.getName() != null ? property.getName().toLowerCase() : ""; + boolean isAvailability = name.contains("availability") || name.contains("success"); + + es.us.isa.qosawarewsbinding.qos.aggretation.AggregationFunction seqFn = + qosmodel.getAggregationFunction(property, es.us.isa.qosawarewsbinding.Sequence.class); + es.us.isa.qosawarewsbinding.qos.aggretation.AggregationFunction loopFn = + qosmodel.getAggregationFunction(property, es.us.isa.qosawarewsbinding.Loop.class); + + boolean seqIsProd = seqFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryAggregationFunction + || seqFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryPowAggregationFunction; + boolean loopIsProd = loopFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryAggregationFunction + || loopFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.ProductoryPowAggregationFunction; + + boolean seqIsSum = seqFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryAggregationFunction + || seqFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.ScaledSumAggregationFunction + || seqFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryPowAggregationFunction; + boolean loopIsSum = loopFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryAggregationFunction + || loopFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.ScaledSumAggregationFunction + || loopFn instanceof es.us.isa.qosawarewsbinding.qos.aggretation.SumatoryPowAggregationFunction; + + double maxVal = 1.0; + double taskSum = 0.0; + for (AbstractWebService aws : market.keySet()) { + double taskMax = 0.0; + for (ConcreteWebService cws : market.get(aws)) { + Double val = (Double) cws.getQoSValue(property); + if (val != null) { + double abs = Math.abs(val.doubleValue()); + if (abs > taskMax) { + taskMax = abs; + } + if (abs > maxVal) { + maxVal = abs; + } + } + } + taskSum += taskMax; + } + + double ub; + if (isAvailability || seqIsProd || loopIsProd) { + ub = 1.0; + } else if (seqIsSum || loopIsSum) { + double loopFactor = 10.0; + ub = Math.max(1.0, taskSum * loopFactor); + } else { + ub = maxVal * 1.5; + } + + ubCache.put(property, ub); + return ub; + } + public String getProblemType() { return "QoS-awareCWSBinding"; } diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/RangeGlobalQoSWSCompositionConstraint.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/RangeGlobalQoSWSCompositionConstraint.java new file mode 100644 index 0000000..3afbb88 --- /dev/null +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/RangeGlobalQoSWSCompositionConstraint.java @@ -0,0 +1,94 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package es.us.isa.qosawarewsbinding.problem; + +import es.us.isa.qosawarewsbinding.problem.QoSAwareWSCompositionProblem; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; + +import java.io.Serializable; +import java.util.Map; + +/** + * + * @author antigravity + */ +public class RangeGlobalQoSWSCompositionConstraint extends WSCompositionConstraint implements Serializable { + + private QoSProperty property; + private Double min; + private Double max; + private BinaryOperator operator; + + public RangeGlobalQoSWSCompositionConstraint() { + this.operator = BinaryOperator.IN_RANGE; + } + + public RangeGlobalQoSWSCompositionConstraint(QoSAwareWSCompositionProblem problem, QoSProperty property, Double min, + Double max, boolean hard) { + super(problem); + this.property = property; + this.min = min; + this.max = max; + this.operator = BinaryOperator.IN_RANGE; + this.setHard(hard); + } + + @Override + public boolean meets(QoSAwareWSCompositionSolution solution) { + return meetingDistance(solution) <= 0; + } + + @Override + public double meetingDistance(QoSAwareWSCompositionSolution solution) { + Double currentValue = problem.getQosmodel().evaluate(solution, property, problem.getStructure()); + return meetingDistance(currentValue); + } + + private double meetingDistance(Double currentValue) { + if (currentValue == null) + return 1.0; // Distance if null? + double val = currentValue.doubleValue(); + + // Distance is how far from range + if (val < min) + return min - val; + if (val > max) + return val - max; + return 0.0; + } + + public QoSProperty getProperty() { + return property; + } + + public void setProperty(QoSProperty property) { + this.property = property; + } + + public Double getMin() { + return min; + } + + public void setMin(Double min) { + this.min = min; + } + + public Double getMax() { + return max; + } + + public void setMax(Double max) { + this.max = max; + } + + public BinaryOperator getOperator() { + return operator; + } + + public void setOperator(BinaryOperator operator) { + this.operator = operator; + } +} diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/SimpleUnfeasibilityPenalizator.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/SimpleUnfeasibilityPenalizator.java new file mode 100644 index 0000000..79f9844 --- /dev/null +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/SimpleUnfeasibilityPenalizator.java @@ -0,0 +1,14 @@ +package es.us.isa.qosawarewsbinding.problem; + +public class SimpleUnfeasibilityPenalizator implements UnfeasibilityPenalizator { + + @Override + public double penalize(double fitness, double feasibilityDistance) { + if (feasibilityDistance > 0) { + // If infeasible, increase the objective by the distance so it is worse. + return fitness + feasibilityDistance; + } + return fitness; + } + +} diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionConstraint.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionConstraint.java index dbf7350..6a46813 100644 --- a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionConstraint.java +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionConstraint.java @@ -19,11 +19,22 @@ public WSCompositionConstraint(QoSAwareWSCompositionProblem problem) { this.problem=problem; } - + + protected WSCompositionConstraint() { + } public abstract boolean meets(QoSAwareWSCompositionSolution solution); public abstract double meetingDistance(QoSAwareWSCompositionSolution solution); + private boolean hard = true; + + public boolean isHard() { + return hard; + } + + public void setHard(boolean hard) { + this.hard = hard; + } } diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionQoSModel.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionQoSModel.java index d226994..fec4e9d 100644 --- a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionQoSModel.java +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/problem/WSCompositionQoSModel.java @@ -21,6 +21,7 @@ import es.us.isa.qosawarewsbinding.WSCompositionStructure; import es.us.isa.qosawarewsbinding.qos.QoSProperty; import es.us.isa.qosawarewsbinding.qos.aggretation.AggregationFunction; +import es.us.isa.qosawarewsbinding.EmptyComponent; import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; /** @@ -114,7 +115,12 @@ public Double evaluate(QoSAwareWSCompositionSolution solution, QoSProperty prope Double result=null; if(component instanceof AbstractWebService) result=(Double)solution.getSelectedService((AbstractWebService)component).getQoSValue(property); - else{ + else if (component instanceof EmptyComponent) { + if (property.getType() == es.us.isa.qosawarewsbinding.qos.QoSPropertyType.POSITIVE) + result = 1.0; + else + result = 0.0; + } else { AggregationFunction aggregationFunction=getAggregationFunction(property,component.getClass()); List partialResults=new LinkedList(); List ponderations=new LinkedList(); diff --git a/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/ScaledSumAggregationFunction.java b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/ScaledSumAggregationFunction.java new file mode 100644 index 0000000..8c222c2 --- /dev/null +++ b/engines/random-search/src/main/java/es/us/isa/qosawarewsbinding/qos/aggretation/ScaledSumAggregationFunction.java @@ -0,0 +1,34 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package es.us.isa.qosawarewsbinding.qos.aggretation; + +import java.util.List; + +/** + * + * @author antigravity + */ +public class ScaledSumAggregationFunction implements AggregationFunction { + + // Singleton? The others were. + private static ScaledSumAggregationFunction instance = new ScaledSumAggregationFunction(); + + public static ScaledSumAggregationFunction getInstance() { + return instance; + } + + @Override + public Double aggregation(List values, List ponderations) { + double result = 0; + for (Double value : values) { + result += value; + } + double factor = 1.0; + if (ponderations != null && !ponderations.isEmpty()) { + factor = ponderations.get(0); + } + return result * factor; + } +} diff --git a/engines/random-search/src/test/java/es/us/isa/qosawarewsbinding/problem/ConstraintsTest.java b/engines/random-search/src/test/java/es/us/isa/qosawarewsbinding/problem/ConstraintsTest.java new file mode 100644 index 0000000..c2b08b4 --- /dev/null +++ b/engines/random-search/src/test/java/es/us/isa/qosawarewsbinding/problem/ConstraintsTest.java @@ -0,0 +1,159 @@ + +package es.us.isa.qosawarewsbinding.problem; + +import static org.junit.Assert.*; +import org.junit.Test; +import java.util.*; + +import es.us.isa.qosawarewsbinding.AbstractWebService; +import es.us.isa.qosawarewsbinding.ConcreteWebService; +import es.us.isa.qosawarewsbinding.solution.QoSAwareWSCompositionSolution; +import es.us.isa.qosawarewsbinding.qos.QoSProperty; +import es.us.isa.qosawarewsbinding.qos.QoSPropertyType; + +public class ConstraintsTest { + + @Test + public void testRangeGlobalConstraint() { + // Setup Problem & QoS Model + QoSProperty cost = new QoSProperty("cost", null, QoSPropertyType.NEGATIVE); + Set properties = new HashSet<>(); + properties.add(cost); + WSCompositionQoSModel qosModel = new WSCompositionQoSModel(properties); + + // Mock Problem to return our QoS Model + QoSAwareWSCompositionProblem problem = new QoSAwareWSCompositionProblem(null, qosModel); + + RangeGlobalQoSWSCompositionConstraint c = new RangeGlobalQoSWSCompositionConstraint(problem, cost, 10.0, 20.0, + true); + + // Mock Solution with mocked evaluation + WSCompositionQoSModel mockModel = new WSCompositionQoSModel(properties) { + @Override + public Double evaluate(QoSAwareWSCompositionSolution solution, QoSProperty property, + es.us.isa.qosawarewsbinding.WSCompositionStructure structure) { + return ((MockSolution) solution).getAggregatedValue(property); + } + }; + problem.setQosmodel(mockModel); + // ... rest of test ... use existing var names + MockSolution val15 = new MockSolution(problem); + val15.setAggregatedValue(cost, 15.0); + assertTrue("Should be satisfied inside range", c.meets(val15)); + + MockSolution val10 = new MockSolution(problem); + val10.setAggregatedValue(cost, 10.0); + assertTrue("Should be satisfied at lower bound", c.meets(val10)); + + MockSolution val20 = new MockSolution(problem); + val20.setAggregatedValue(cost, 20.0); + assertTrue("Should be satisfied at upper bound", c.meets(val20)); + + MockSolution val9 = new MockSolution(problem); + val9.setAggregatedValue(cost, 9.9); + assertFalse("Should fail below range", c.meets(val9)); + + assertEquals(0.1, c.meetingDistance(val9), 0.001); + + MockSolution val21 = new MockSolution(problem); + val21.setAggregatedValue(cost, 20.1); + assertFalse("Should fail above range", c.meets(val21)); + assertEquals(0.1, c.meetingDistance(val21), 0.001); + } + + @Test + public void testLocalConstraint() { + QoSProperty cost = new QoSProperty("cost", null, QoSPropertyType.NEGATIVE); + QoSAwareWSCompositionProblem problem = new QoSAwareWSCompositionProblem(null, null); + AbstractWebService task1 = new AbstractWebService("T1"); + + LocalQoSWSCompositionConstraint c = new LocalQoSWSCompositionConstraint(problem, cost, + BinaryOperator.LOWEREQUAL, 10.0, task1, true); + + MockSolution sol = new MockSolution(problem); + ConcreteWebService s1 = new ConcreteWebService("S1", task1); + s1.setQoSValue(cost, 5.0); + sol.setSelectedService(task1, s1); + + assertTrue("5.0 <= 10.0", c.meets(sol)); + + s1.setQoSValue(cost, 15.0); + assertFalse("15.0 <= 10.0 should fail", c.meets(sol)); + assertEquals(5.0, c.meetingDistance(sol), 0.001); + } + + @Test + public void testDependencyConstraint() { + QoSAwareWSCompositionProblem problem = new QoSAwareWSCompositionProblem(null, null); + AbstractWebService t1 = new AbstractWebService("T1"); + AbstractWebService t2 = new AbstractWebService("T2"); + List tasks = Arrays.asList(t1, t2); + + // Different Providers + ProviderRelationWSCompositionConstraint cDiff = new ProviderRelationWSCompositionConstraint( + problem, + ProviderRelationWSCompositionConstraint.Type.DIFFERENT_PROVIDER, + tasks, + true); + + MockSolution sol = new MockSolution(problem); + ConcreteWebService s1 = new ConcreteWebService("s1_P1", t1); + ConcreteWebService s2 = new ConcreteWebService("s2_P2", t2); + + sol.setSelectedService(t1, s1); + sol.setSelectedService(t2, s2); + + assertTrue("Different providers", cDiff.meets(sol)); + + ConcreteWebService s3 = new ConcreteWebService("s3_P1", t2); // Same provider P1 + sol.setSelectedService(t2, s3); + + assertFalse("Same provider but expected different", cDiff.meets(sol)); + + // Same Provider + ProviderRelationWSCompositionConstraint cSame = new ProviderRelationWSCompositionConstraint( + problem, + ProviderRelationWSCompositionConstraint.Type.SAME_PROVIDER, + tasks, + true); + + assertTrue("Same provider P1", cSame.meets(sol)); + + sol.setSelectedService(t2, s2); // P2 + assertFalse("Different provider but expected same", cSame.meets(sol)); + } + + // Stub Solution + static class MockSolution extends QoSAwareWSCompositionSolution { + private Map selection = new HashMap<>(); + private Map aggregated = new HashMap<>(); + + public MockSolution(QoSAwareWSCompositionProblem problem) { + super(problem); + } + + @Override + public ConcreteWebService getSelectedService(AbstractWebService aws) { + return selection.get(aws); + } + + @Override + public void setSelectedService(AbstractWebService aws, ConcreteWebService cws) { + selection.put(aws, cws); + } + + public void setAggregatedValue(QoSProperty p, Double v) { + aggregated.put(p, v); + } + + public Double getAggregatedValue(QoSProperty p) { + return aggregated.get(p); + } + + @Override + public es.us.isa.qosawarewsbinding.solution.Solution createRandom() { + return null; // Not needed + } + + } +} diff --git a/examples/common-basic.json b/examples/common-basic.json deleted file mode 100644 index 71b0486..0000000 --- a/examples/common-basic.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "metadata": { - "id": "01_safe", - "name": "01_safe", - "version": "1.0", - "created_at": "2026-01-26T12:00:00Z" - }, - "providers": [ - { - "id": "P1", - "name": "P1" - } - ], - "tasks": [ - { - "id": "T1", - "name": "T1" - } - ], - "candidates": [ - { - "id": "C1", - "task_id": "T1", - "provider_id": "P1", - "name": "C1", - "features": { - "cost": 10, - "time": 10 - } - } - ], - "features": [ - { - "id": "cost", - "name": "cost", - "unit": "usd", - "scale": "ratio", - "valid_range": { - "min": 0, - "max": 1000 - }, - "direction": "minimize" - }, - { - "id": "time", - "name": "time", - "unit": "ms", - "scale": "ratio", - "valid_range": { - "min": 0, - "max": 1000 - }, - "direction": "minimize" - } - ], - "composition": { - "type": "structured", - "root": { - "id": "root", - "kind": "TASK", - "task_id": "T1" - } - }, - "aggregation_policies": { - "cost": { - "neutral": 0, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "sum" - }, - "loop": { - "fn": "sum" - } - }, - "normalize": { - "type": "minmax", - "bounds": { - "min": 0, - "max": 1000 - } - } - }, - "time": { - "neutral": 0, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "sum" - }, - "loop": { - "fn": "sum" - } - }, - "normalize": { - "type": "minmax", - "bounds": { - "min": 0, - "max": 1000 - } - } - } - }, - "objective": { - "type": "weighted_sum", - "weights": { - "cost": 0.5, - "time": 0.5 - }, - "normalized": true - }, - "constraints": [] -} \ No newline at end of file diff --git a/examples/common-huge.json b/examples/common-huge.json deleted file mode 100644 index 4fdf361..0000000 --- a/examples/common-huge.json +++ /dev/null @@ -1,560 +0,0 @@ -{ - "metadata": { - "id": "huge-common", - "name": "Huge common", - "version": "1.0", - "created_at": "2026-01-01T00:00:00Z" - }, - "tasks": [ - { - "id": "T1", - "name": "Task 1" - }, - { - "id": "T2", - "name": "Task 2" - }, - { - "id": "T3", - "name": "Task 3" - }, - { - "id": "T4", - "name": "Task 4" - }, - { - "id": "T5", - "name": "Task 5" - }, - { - "id": "T6", - "name": "Task 6" - }, - { - "id": "T7", - "name": "Task 7" - } - ], - "providers": [ - { - "id": "P1", - "name": "Provider 1" - }, - { - "id": "P2", - "name": "Provider 2" - }, - { - "id": "P3", - "name": "Provider 3" - } - ], - "candidates": [ - { - "id": "C1", - "task_id": "T1", - "provider_id": "P1", - "features": { - "cost": 10, - "latency": 5, - "reliability": 0.9, - "availability": 0.99, - "energy": 2 - } - }, - { - "id": "C2", - "task_id": "T1", - "provider_id": "P2", - "features": { - "cost": 20, - "latency": 10, - "reliability": 0.9, - "availability": 0.99, - "energy": 4 - } - }, - { - "id": "C3", - "task_id": "T1", - "provider_id": "P3", - "features": { - "cost": 30, - "latency": 15, - "reliability": 0.9, - "availability": 0.99, - "energy": 6 - } - }, - { - "id": "C4", - "task_id": "T2", - "provider_id": "P1", - "features": { - "cost": 40, - "latency": 20, - "reliability": 0.9, - "availability": 0.99, - "energy": 8 - } - }, - { - "id": "C5", - "task_id": "T2", - "provider_id": "P2", - "features": { - "cost": 50, - "latency": 25, - "reliability": 0.9, - "availability": 0.99, - "energy": 10 - } - }, - { - "id": "C6", - "task_id": "T2", - "provider_id": "P3", - "features": { - "cost": 60, - "latency": 30, - "reliability": 0.9, - "availability": 0.99, - "energy": 12 - } - }, - { - "id": "C7", - "task_id": "T3", - "provider_id": "P1", - "features": { - "cost": 70, - "latency": 35, - "reliability": 0.9, - "availability": 0.99, - "energy": 14 - } - }, - { - "id": "C8", - "task_id": "T3", - "provider_id": "P2", - "features": { - "cost": 80, - "latency": 40, - "reliability": 0.9, - "availability": 0.99, - "energy": 16 - } - }, - { - "id": "C9", - "task_id": "T3", - "provider_id": "P3", - "features": { - "cost": 90, - "latency": 45, - "reliability": 0.9, - "availability": 0.99, - "energy": 18 - } - }, - { - "id": "C10", - "task_id": "T4", - "provider_id": "P1", - "features": { - "cost": 100, - "latency": 50, - "reliability": 0.9, - "availability": 0.99, - "energy": 20 - } - }, - { - "id": "C11", - "task_id": "T4", - "provider_id": "P2", - "features": { - "cost": 110, - "latency": 55, - "reliability": 0.9, - "availability": 0.99, - "energy": 22 - } - }, - { - "id": "C12", - "task_id": "T4", - "provider_id": "P3", - "features": { - "cost": 120, - "latency": 60, - "reliability": 0.9, - "availability": 0.99, - "energy": 24 - } - }, - { - "id": "C13", - "task_id": "T5", - "provider_id": "P1", - "features": { - "cost": 130, - "latency": 65, - "reliability": 0.9, - "availability": 0.99, - "energy": 26 - } - }, - { - "id": "C14", - "task_id": "T5", - "provider_id": "P2", - "features": { - "cost": 140, - "latency": 70, - "reliability": 0.9, - "availability": 0.99, - "energy": 28 - } - }, - { - "id": "C15", - "task_id": "T5", - "provider_id": "P3", - "features": { - "cost": 150, - "latency": 75, - "reliability": 0.9, - "availability": 0.99, - "energy": 30 - } - }, - { - "id": "C16", - "task_id": "T6", - "provider_id": "P1", - "features": { - "cost": 160, - "latency": 80, - "reliability": 0.9, - "availability": 0.99, - "energy": 32 - } - }, - { - "id": "C17", - "task_id": "T6", - "provider_id": "P2", - "features": { - "cost": 170, - "latency": 85, - "reliability": 0.9, - "availability": 0.99, - "energy": 34 - } - }, - { - "id": "C18", - "task_id": "T6", - "provider_id": "P3", - "features": { - "cost": 180, - "latency": 90, - "reliability": 0.9, - "availability": 0.99, - "energy": 36 - } - }, - { - "id": "C19", - "task_id": "T7", - "provider_id": "P1", - "features": { - "cost": 190, - "latency": 95, - "reliability": 0.9, - "availability": 0.99, - "energy": 38 - } - }, - { - "id": "C20", - "task_id": "T7", - "provider_id": "P2", - "features": { - "cost": 200, - "latency": 100, - "reliability": 0.9, - "availability": 0.99, - "energy": 40 - } - }, - { - "id": "C21", - "task_id": "T7", - "provider_id": "P3", - "features": { - "cost": 210, - "latency": 105, - "reliability": 0.9, - "availability": 0.99, - "energy": 42 - } - } - ], - "features": [ - { - "id": "cost", - "name": "Cost", - "direction": "minimize", - "scale": "ratio", - "unit": "USD", - "valid_range": { - "min": 0, - "max": 100000 - } - }, - { - "id": "latency", - "name": "Latency", - "direction": "minimize", - "scale": "ratio", - "unit": "ms", - "valid_range": { - "min": 0, - "max": 10000 - } - }, - { - "id": "reliability", - "name": "Reliability", - "direction": "maximize", - "scale": "ratio", - "unit": "%", - "valid_range": { - "min": 0, - "max": 1 - } - }, - { - "id": "availability", - "name": "Availability", - "direction": "maximize", - "scale": "ratio", - "unit": "%", - "valid_range": { - "min": 0, - "max": 1 - } - }, - { - "id": "energy", - "name": "Energy", - "direction": "minimize", - "scale": "ratio", - "unit": "J", - "valid_range": { - "min": 0, - "max": 10000 - } - } - ], - "composition": { - "type": "structured", - "root": { - "id": "root_seq", - "kind": "SEQ", - "children": [ - { - "id": "n1", - "kind": "TASK", - "task_id": "T1" - }, - { - "id": "n2_and", - "kind": "AND", - "children": [ - { - "id": "n2a", - "kind": "TASK", - "task_id": "T2" - }, - { - "id": "n2b", - "kind": "TASK", - "task_id": "T3" - } - ] - }, - { - "id": "n3_xor", - "kind": "XOR", - "branches": [ - { - "p": 0.5, - "child": { - "id": "n3a", - "kind": "TASK", - "task_id": "T4" - } - }, - { - "p": 0.5, - "child": { - "id": "n3b", - "kind": "TASK", - "task_id": "T5" - } - } - ] - }, - { - "id": "n4_loop", - "kind": "LOOP", - "expected_iterations": 3, - "body": { - "id": "n4_inner_seq", - "kind": "SEQ", - "children": [ - { - "id": "n4a", - "kind": "TASK", - "task_id": "T6" - }, - { - "id": "n4b", - "kind": "TASK", - "task_id": "T7" - } - ] - } - } - ] - } - }, - "aggregation_policies": { - "cost": { - "neutral": 0, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - }, - "latency": { - "neutral": 0, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - }, - "reliability": { - "neutral": 1, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - }, - "availability": { - "neutral": 1, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - }, - "energy": { - "neutral": 0, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - } - }, - "objective": { - "type": "weighted_sum", - "weights": { - "cost": 1 - }, - "normalized": true - }, - "constraints": [ - { - "id": "c0", - "kind": "attribute_bound", - "scope": "global", - "attribute_id": "cost", - "op": "<=", - "value": 50000 - } - ] -} \ No newline at end of file diff --git a/examples/common-mixed.json b/examples/common-mixed.json deleted file mode 100644 index 130d04c..0000000 --- a/examples/common-mixed.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "metadata": { - "id": "05_safe", - "name": "05_safe", - "version": "1.0", - "created_at": "2026-01-26T12:00:00Z" - }, - "providers": [ - { - "id": "P1", - "name": "P1" - } - ], - "tasks": [ - { - "id": "T1", - "name": "T1" - } - ], - "candidates": [ - { - "id": "C1", - "task_id": "T1", - "provider_id": "P1", - "name": "C1", - "features": { - "cost": 10, - "time": 10 - } - } - ], - "features": [ - { - "id": "cost", - "name": "cost", - "unit": "usd", - "scale": "ratio", - "valid_range": { - "min": 0, - "max": 1000 - }, - "direction": "minimize" - }, - { - "id": "time", - "name": "time", - "unit": "ms", - "scale": "ratio", - "valid_range": { - "min": 0, - "max": 1000 - }, - "direction": "minimize" - } - ], - "composition": { - "type": "structured", - "root": { - "id": "root", - "kind": "TASK", - "task_id": "T1" - } - }, - "aggregation_policies": { - "cost": { - "neutral": 0, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "sum" - }, - "loop": { - "fn": "sum" - } - }, - "normalize": { - "type": "minmax", - "bounds": { - "min": 0, - "max": 1000 - } - } - }, - "time": { - "neutral": 0, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "sum" - }, - "loop": { - "fn": "sum" - } - }, - "normalize": { - "type": "minmax", - "bounds": { - "min": 0, - "max": 1000 - } - } - } - }, - "objective": { - "type": "weighted_sum", - "weights": { - "cost": 0.5, - "time": 0.5 - }, - "normalized": true - }, - "constraints": [] -} \ No newline at end of file diff --git a/examples/demo/01_simple_seq.json b/examples/demo/01_simple_seq.json new file mode 100644 index 0000000..cceb406 --- /dev/null +++ b/examples/demo/01_simple_seq.json @@ -0,0 +1,61 @@ +{ + "metadata": { + "id": "demo_01_simple_seq", + "name": "01. Simple Sequence", + "version": "1.0.0", + "created_at": "2026-02-10T12:00:00Z", + "description": "A basic sequential composition of 3 tasks. This is the simplest possible workflow.", + "level": "beginner" + }, + "features": [ + { + "id": "latency", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": {"min": 0, "max": 1000} + } + ], + "providers": [ + {"id": "p1", "name": "Provider 1"} + ], + "tasks": [ + {"id": "t1", "name": "Task 1"}, + {"id": "t2", "name": "Task 2"}, + {"id": "t3", "name": "Task 3"} + ], + "candidates": [ + {"id": "c1a", "task_id": "t1", "provider_id": "p1", "name": "Service 1A", "features": {"latency": 10}}, + {"id": "c1b", "task_id": "t1", "provider_id": "p1", "name": "Service 1B", "features": {"latency": 20}}, + {"id": "c2a", "task_id": "t2", "provider_id": "p1", "name": "Service 2A", "features": {"latency": 15}}, + {"id": "c3a", "task_id": "t3", "provider_id": "p1", "name": "Service 3A", "features": {"latency": 5}} + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "root", + "kind": "SEQ", + "children": [ + {"id": "n1", "kind": "TASK", "task_id": "t1"}, + {"id": "n2", "kind": "TASK", "task_id": "t2"}, + {"id": "n3", "kind": "TASK", "task_id": "t3"} + ] + } + }, + "aggregation_policies": { + "latency": { + "neutral": 0, + "compose": { + "seq": {"fn": "SUM"}, + "and": {"fn": "MAX"}, + "loop": {"fn": "SCALED_SUM"} + } + } + }, + "objective": { + "type": "MONO", + "targets": ["latency"], + "weights": {"latency": 1.0} + } +} diff --git a/examples/demo/02_parallel.json b/examples/demo/02_parallel.json new file mode 100644 index 0000000..414b4fc --- /dev/null +++ b/examples/demo/02_parallel.json @@ -0,0 +1,57 @@ +{ + "metadata": { + "id": "demo_02_parallel", + "name": "02. Parallel Flow", + "version": "1.0.0", + "created_at": "2026-02-10T12:00:00Z", + "description": "Tasks executing in parallel. The latency of the parallel block is the maximum of its children.", + "level": "beginner" + }, + "features": [ + { + "id": "latency", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": {"min": 0, "max": 1000} + } + ], + "providers": [ + {"id": "p1", "name": "Provider 1"} + ], + "tasks": [ + {"id": "t1", "name": "Task 1 (Slow)"}, + {"id": "t2", "name": "Task 2 (Fast)"} + ], + "candidates": [ + {"id": "c1", "task_id": "t1", "provider_id": "p1", "name": "SVC 1", "features": {"latency": 100}}, + {"id": "c2", "task_id": "t2", "provider_id": "p1", "name": "SVC 2", "features": {"latency": 20}} + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "root", + "kind": "AND", + "children": [ + {"id": "n1", "kind": "TASK", "task_id": "t1"}, + {"id": "n2", "kind": "TASK", "task_id": "t2"} + ] + } + }, + "aggregation_policies": { + "latency": { + "neutral": 0, + "compose": { + "seq": {"fn": "SUM"}, + "and": {"fn": "MAX"}, + "loop": {"fn": "SCALED_SUM"} + } + } + }, + "objective": { + "type": "MONO", + "targets": ["latency"], + "weights": {"latency": 1.0} + } +} diff --git a/examples/demo/03_xor_choice.json b/examples/demo/03_xor_choice.json new file mode 100644 index 0000000..6156c02 --- /dev/null +++ b/examples/demo/03_xor_choice.json @@ -0,0 +1,63 @@ +{ + "metadata": { + "id": "demo_03_xor", + "name": "03. XOR Choice", + "version": "1.0.0", + "created_at": "2026-02-10T12:00:00Z", + "description": "Exclusive choice between paths based on probability. We want to maximize availability.", + "level": "intermediate" + }, + "features": [ + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": {"min": 0, "max": 1} + } + ], + "providers": [ + {"id": "p1", "name": "Provider 1"} + ], + "tasks": [ + {"id": "t_common", "name": "Common Task"}, + {"id": "t_path_a", "name": "Path A Task"}, + {"id": "t_path_b", "name": "Path B Task"} + ], + "candidates": [ + {"id": "c_common", "task_id": "t_common", "provider_id": "p1", "name": "SVC Common", "features": {"availability": 0.99}}, + {"id": "c_a", "task_id": "t_path_a", "provider_id": "p1", "name": "SVC A", "features": {"availability": 0.95}}, + {"id": "c_b", "task_id": "t_path_b", "provider_id": "p1", "name": "SVC B", "features": {"availability": 0.999}} + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "root", + "kind": "SEQ", + "children": [ + {"id": "n1", "kind": "TASK", "task_id": "t_common"}, + {"id": "n_choice", "kind": "XOR", "branches": [ + {"p": 0.8, "child": {"id": "na", "kind": "TASK", "task_id": "t_path_a"}}, + {"p": 0.2, "child": {"id": "nb", "kind": "TASK", "task_id": "t_path_b"}} + ]} + ] + } + }, + "aggregation_policies": { + "availability": { + "neutral": 1, + "compose": { + "seq": {"fn": "PRODUCT"}, + "and": {"fn": "PRODUCT"}, + "loop": {"fn": "SCALED_PRODUCT"}, + "xor": {"fn": "SCALED_SUM"} + } + } + }, + "objective": { + "type": "MONO", + "targets": ["availability"], + "weights": {"availability": 1.0} + } +} diff --git a/examples/demo/04_conflict.json b/examples/demo/04_conflict.json new file mode 100644 index 0000000..ff75b8d --- /dev/null +++ b/examples/demo/04_conflict.json @@ -0,0 +1,60 @@ +{ + "metadata": { + "id": "demo_04_conflict", + "name": "04. Conflict (Infeasible)", + "version": "1.0.0", + "created_at": "2026-02-10T12:00:00Z", + "description": "An example where constraints make a solution impossible. All candidates have non-negative cost, but we constrain globally to cost < 0.", + "level": "intermediate" + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "eur", + "scale": "RATIO", + "valid_range": {"min": 0, "max": 1000} + } + ], + "providers": [{"id": "p1", "name": "Provider 1"}], + "tasks": [{"id": "t1", "name": "Expensive Task"}], + "candidates": [ + {"id": "c1", "task_id": "t1", "provider_id": "p1", "name": "Cheap Svc", "features": {"cost": 100}}, + {"id": "c2", "task_id": "t1", "provider_id": "p1", "name": "Expensive Svc", "features": {"cost": 200}} + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "root", + "kind": "TASK", + "task_id": "t1" + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": {"fn": "SUM"}, + "and": {"fn": "SUM"}, + "loop": {"fn": "SCALED_SUM"} + } + } + }, + "constraints": [ + { + "id": "c_impossible", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<", + "value": 0, + "hard": true + } + ], + "objective": { + "type": "MONO", + "targets": ["cost"], + "weights": {"cost": 1.0} + } +} diff --git a/examples/demo/05_multi_obj.json b/examples/demo/05_multi_obj.json new file mode 100644 index 0000000..7e1a7d1 --- /dev/null +++ b/examples/demo/05_multi_obj.json @@ -0,0 +1,53 @@ +{ + "metadata": { + "id": "demo_05_multi_obj", + "name": "05. Multi Objective", + "version": "1.0.0", + "created_at": "2026-02-10T12:00:00Z", + "description": "Trade-off between Cost and Latency using a MONO (weighted-sum) objective. This is resolvable by current engines.", + "level": "intermediate" + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "eur", + "scale": "RATIO", + "valid_range": {"min": 0, "max": 100} + }, + { + "id": "latency", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": {"min": 0, "max": 100} + } + ], + "providers": [{"id": "p1", "name": "P1"}], + "tasks": [{"id": "t1", "name": "Task 1"}], + "candidates": [ + {"id": "c_fast_expensive", "task_id": "t1", "provider_id": "p1", "name": "Fast & Expensive", "features": {"cost": 90, "latency": 10}}, + {"id": "c_slow_cheap", "task_id": "t1", "provider_id": "p1", "name": "Slow & Cheap", "features": {"cost": 10, "latency": 90}}, + {"id": "c_balanced", "task_id": "t1", "provider_id": "p1", "name": "Balanced", "features": {"cost": 50, "latency": 50}}, + {"id": "c_bad", "task_id": "t1", "provider_id": "p1", "name": "Dominated (Bad)", "features": {"cost": 100, "latency": 100}} + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "root", + "kind": "TASK", + "task_id": "t1" + } + }, + "aggregation_policies": { + "cost": {"neutral": 0, "compose": { "seq": {"fn": "SUM"}, "and": {"fn": "SUM"}, "loop": {"fn": "SCALED_SUM"} } }, + "latency": {"neutral": 0, "compose": { "seq": {"fn": "SUM"}, "and": {"fn": "MAX"}, "loop": {"fn": "SCALED_SUM"} } } + }, + "objective": { + "type": "MONO", + "targets": ["cost", "latency"], + "weights": {"cost": 0.5, "latency": 0.5} + } +} diff --git a/examples/demo/05_single_obj_various.json b/examples/demo/05_single_obj_various.json new file mode 100644 index 0000000..7e1a7d1 --- /dev/null +++ b/examples/demo/05_single_obj_various.json @@ -0,0 +1,53 @@ +{ + "metadata": { + "id": "demo_05_multi_obj", + "name": "05. Multi Objective", + "version": "1.0.0", + "created_at": "2026-02-10T12:00:00Z", + "description": "Trade-off between Cost and Latency using a MONO (weighted-sum) objective. This is resolvable by current engines.", + "level": "intermediate" + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "eur", + "scale": "RATIO", + "valid_range": {"min": 0, "max": 100} + }, + { + "id": "latency", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": {"min": 0, "max": 100} + } + ], + "providers": [{"id": "p1", "name": "P1"}], + "tasks": [{"id": "t1", "name": "Task 1"}], + "candidates": [ + {"id": "c_fast_expensive", "task_id": "t1", "provider_id": "p1", "name": "Fast & Expensive", "features": {"cost": 90, "latency": 10}}, + {"id": "c_slow_cheap", "task_id": "t1", "provider_id": "p1", "name": "Slow & Cheap", "features": {"cost": 10, "latency": 90}}, + {"id": "c_balanced", "task_id": "t1", "provider_id": "p1", "name": "Balanced", "features": {"cost": 50, "latency": 50}}, + {"id": "c_bad", "task_id": "t1", "provider_id": "p1", "name": "Dominated (Bad)", "features": {"cost": 100, "latency": 100}} + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "root", + "kind": "TASK", + "task_id": "t1" + } + }, + "aggregation_policies": { + "cost": {"neutral": 0, "compose": { "seq": {"fn": "SUM"}, "and": {"fn": "SUM"}, "loop": {"fn": "SCALED_SUM"} } }, + "latency": {"neutral": 0, "compose": { "seq": {"fn": "SUM"}, "and": {"fn": "MAX"}, "loop": {"fn": "SCALED_SUM"} } } + }, + "objective": { + "type": "MONO", + "targets": ["cost", "latency"], + "weights": {"cost": 0.5, "latency": 0.5} + } +} diff --git a/examples/demo/06_loops.json b/examples/demo/06_loops.json new file mode 100644 index 0000000..8cbc3b7 --- /dev/null +++ b/examples/demo/06_loops.json @@ -0,0 +1,42 @@ +{ + "metadata": { + "id": "demo_06_loops", + "name": "06. Loops", + "version": "1.0.0", + "created_at": "2026-02-10T12:00:00Z", + "description": "Composition with a loop structure. Loops aggregate values based on expected iterations or bounds (scaled sum/product).", + "level": "advanced" + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "eur", + "scale": "RATIO", + "valid_range": {"min": 0, "max": 1000} + } + ], + "providers": [{"id": "p1", "name": "P1"}], + "tasks": [{"id": "t1", "name": "Repeated Task"}], + "candidates": [ + {"id": "c1", "task_id": "t1", "provider_id": "p1", "name": "Service", "features": {"cost": 5}} + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "loop", + "kind": "LOOP", + "body": {"id": "n1", "kind": "TASK", "task_id": "t1"}, + "expected_iterations": 10 + } + }, + "aggregation_policies": { + "cost": {"neutral": 0, "compose": { "seq": {"fn": "SUM"}, "and": {"fn": "SUM"}, "loop": {"fn": "SCALED_SUM"} } } + }, + "objective": { + "type": "MONO", + "targets": ["cost"], + "weights": {"cost": 1.0} + } +} diff --git a/examples/demo/07_soft_constraints.json b/examples/demo/07_soft_constraints.json new file mode 100644 index 0000000..7e7fb91 --- /dev/null +++ b/examples/demo/07_soft_constraints.json @@ -0,0 +1,49 @@ +{ + "metadata": { + "id": "demo_07_soft", + "name": "07. Soft Constraints", + "version": "1.0.0", + "created_at": "2026-02-10T12:00:00Z", + "description": "Demonstrates soft constraints. A soft constraint violation adds a penalty to the objective function, but does not invalidate the solution.", + "level": "intermediate" + }, + "features": [ + { + "id": "latency", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": {"min": 0, "max": 1000} + } + ], + "providers": [{"id": "p1", "name": "P1"}], + "tasks": [{"id": "t1", "name": "Task 1"}], + "candidates": [ + {"id": "c1", "task_id": "t1", "provider_id": "p1", "name": "Fast (Valid)", "features": {"latency": 40}}, + {"id": "c2", "task_id": "t1", "provider_id": "p1", "name": "Slow (Soft Violation)", "features": {"latency": 60}} + ], + "composition": { + "type": "STRUCTURED", + "root": {"id": "n1", "kind": "TASK", "task_id": "t1"} + }, + "aggregation_policies": { + "latency": {"neutral": 0, "compose": { "seq": {"fn": "SUM"}, "and": {"fn": "MAX"}, "loop": {"fn": "SCALED_SUM"} } } + }, + "constraints": [ + { + "id": "c_soft_lat", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency", + "op": "<=", + "value": 50, + "hard": false + } + ], + "objective": { + "type": "MONO", + "targets": ["latency"], + "weights": {"latency": 1.0} + } +} diff --git a/examples/demo/08_dependencies.json b/examples/demo/08_dependencies.json new file mode 100644 index 0000000..fb927c4 --- /dev/null +++ b/examples/demo/08_dependencies.json @@ -0,0 +1,55 @@ +{ + "metadata": { + "id": "demo_08_dependencies", + "name": "08. Dependencies", + "version": "1.0.0", + "created_at": "2026-02-10T12:00:00Z", + "description": "Constraints on provider selection. We enforce that Task 1 and Task 2 must be served by the SAME provider.", + "level": "intermediate" + }, + "features": [ + {"id": "cost", "name": "Cost", "direction": "MINIMIZE", "unit": "eur", "scale": "RATIO", "valid_range": {"min": 0, "max": 100}} + ], + "providers": [ + {"id": "pA", "name": "Provider A"}, + {"id": "pB", "name": "Provider B"} + ], + "tasks": [ + {"id": "t1", "name": "Task 1"}, + {"id": "t2", "name": "Task 2"} + ], + "candidates": [ + {"id": "c1_A", "task_id": "t1", "provider_id": "pA", "name": "T1 by A", "features": {"cost": 10}}, + {"id": "c1_B", "task_id": "t1", "provider_id": "pB", "name": "T1 by B", "features": {"cost": 20}}, + {"id": "c2_A", "task_id": "t2", "provider_id": "pA", "name": "T2 by A", "features": {"cost": 10}}, + {"id": "c2_B", "task_id": "t2", "provider_id": "pB", "name": "T2 by B", "features": {"cost": 5}} + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "seq", + "kind": "SEQ", + "children": [ + {"id": "n1", "kind": "TASK", "task_id": "t1"}, + {"id": "n2", "kind": "TASK", "task_id": "t2"} + ] + } + }, + "aggregation_policies": { + "cost": {"neutral": 0, "compose": { "seq": {"fn": "SUM"}, "and": {"fn": "SUM"}, "loop": {"fn": "SCALED_SUM"} } } + }, + "constraints": [ + { + "id": "c_same_prov", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": ["t1", "t2"], + "hard": true + } + ], + "objective": { + "type": "MONO", + "targets": ["cost"], + "weights": {"cost": 1.0} + } +} diff --git a/examples/demo/09_mixed.json b/examples/demo/09_mixed.json new file mode 100644 index 0000000..ca0c29a --- /dev/null +++ b/examples/demo/09_mixed.json @@ -0,0 +1,200 @@ +{ + "metadata": { + "id": "demo_09_mixed", + "name": "09. Mixed Complexity", + "version": "1.0.0", + "created_at": "2026-02-10T12:00:00Z", + "description": "Combines Parallel, XOR, Dependencies, and Global + Local Constraints.", + "level": "advanced" + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "$", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "rel", + "name": "Reliability", + "direction": "MAXIMIZE", + "unit": "%", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + } + ], + "providers": [ + { + "id": "p1", + "name": "P1" + } + ], + "tasks": [ + { + "id": "t1", + "name": "T1" + }, + { + "id": "t2", + "name": "T2" + }, + { + "id": "t3", + "name": "T3" + } + ], + "candidates": [ + { + "id": "c1a", + "task_id": "t1", + "provider_id": "p1", + "name": "C1A", + "features": { + "cost": 100, + "rel": 0.99 + } + }, + { + "id": "c1b", + "task_id": "t1", + "provider_id": "p1", + "name": "C1B", + "features": { + "cost": 50, + "rel": 0.90 + } + }, + { + "id": "c2a", + "task_id": "t2", + "provider_id": "p1", + "name": "C2A", + "features": { + "cost": 100, + "rel": 0.99 + } + }, + { + "id": "c2b", + "task_id": "t2", + "provider_id": "p1", + "name": "C2B", + "features": { + "cost": 50, + "rel": 0.90 + } + }, + { + "id": "c3", + "task_id": "t3", + "provider_id": "p1", + "name": "C3", + "features": { + "cost": 10, + "rel": 0.99 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "seq", + "kind": "SEQ", + "children": [ + { + "id": "n1", + "kind": "TASK", + "task_id": "t1" + }, + { + "id": "xor", + "kind": "XOR", + "branches": [ + { + "p": 0.5, + "child": { + "id": "n2", + "kind": "TASK", + "task_id": "t2" + } + }, + { + "p": 0.5, + "child": { + "id": "n3", + "kind": "TASK", + "task_id": "t3" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "rel": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "c1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 150, + "hard": true + } + ], + "objective": { + "type": "MONO", + "targets": [ + "rel", + "cost" + ], + "weights": { + "rel": 0.8, + "cost": 0.2 + } + } +} \ No newline at end of file diff --git a/examples/demo/10_large_scale.json b/examples/demo/10_large_scale.json new file mode 100644 index 0000000..1f59bad --- /dev/null +++ b/examples/demo/10_large_scale.json @@ -0,0 +1,627 @@ +{ + "metadata": { + "id": "demo_10_large_scale", + "name": "10. Large Scale (Complex)", + "version": "1.1.0", + "created_at": "2026-02-11T12:00:00Z", + "description": "A complex composition with 10 tasks, mixed control flow (SEQ, AND, XOR, LOOP), and 4 QoS features. 3 candidates per task.", + "level": "expert" + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "USD", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "time", + "name": "Response Time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "reliability", + "name": "Reliability", + "direction": "MAXIMIZE", + "unit": "%", + "scale": "RATIO", + "valid_range": { + "min": 0.5, + "max": 1.0 + } + }, + { + "id": "reputation", + "name": "Reputation", + "direction": "MAXIMIZE", + "unit": "scale", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10 + } + } + ], + "providers": [ + { + "id": "p1", + "name": "Provider 1" + } + ], + "tasks": [ + { + "id": "t1", + "name": "Authentication" + }, + { + "id": "t2", + "name": "Credit Check" + }, + { + "id": "t3", + "name": "Inventory Check" + }, + { + "id": "t4", + "name": "Standard Ship" + }, + { + "id": "t5", + "name": "Express Ship" + }, + { + "id": "t6", + "name": "Payment Processing" + }, + { + "id": "t7", + "name": "Email Notification" + }, + { + "id": "t8", + "name": "SMS Notification" + }, + { + "id": "t9", + "name": "Update CRM" + }, + { + "id": "t10", + "name": "Analytics Log" + } + ], + "candidates": [ + { + "id": "c1_1", + "task_id": "t1", + "provider_id": "p1", + "name": "Auth Service A", + "features": { + "cost": 1.0, + "time": 100, + "reliability": 0.999, + "reputation": 9.0 + } + }, + { + "id": "c1_2", + "task_id": "t1", + "provider_id": "p1", + "name": "Auth Service B", + "features": { + "cost": 0.5, + "time": 300, + "reliability": 0.95, + "reputation": 7.5 + } + }, + { + "id": "c1_3", + "task_id": "t1", + "provider_id": "p1", + "name": "Auth Service C", + "features": { + "cost": 0.1, + "time": 500, + "reliability": 0.90, + "reputation": 6.0 + } + }, + { + "id": "c2_1", + "task_id": "t2", + "provider_id": "p1", + "name": "Credit A", + "features": { + "cost": 2.0, + "time": 200, + "reliability": 0.98, + "reputation": 8.0 + } + }, + { + "id": "c2_2", + "task_id": "t2", + "provider_id": "p1", + "name": "Credit B", + "features": { + "cost": 1.5, + "time": 250, + "reliability": 0.97, + "reputation": 8.5 + } + }, + { + "id": "c2_3", + "task_id": "t2", + "provider_id": "p1", + "name": "Credit C", + "features": { + "cost": 1.0, + "time": 400, + "reliability": 0.95, + "reputation": 7.0 + } + }, + { + "id": "c3_1", + "task_id": "t3", + "provider_id": "p1", + "name": "Inventory A", + "features": { + "cost": 0.5, + "time": 50, + "reliability": 0.99, + "reputation": 9.5 + } + }, + { + "id": "c3_2", + "task_id": "t3", + "provider_id": "p1", + "name": "Inventory B", + "features": { + "cost": 0.2, + "time": 100, + "reliability": 0.98, + "reputation": 8.0 + } + }, + { + "id": "c3_3", + "task_id": "t3", + "provider_id": "p1", + "name": "Inventory C", + "features": { + "cost": 0.1, + "time": 150, + "reliability": 0.90, + "reputation": 6.5 + } + }, + { + "id": "c4_1", + "task_id": "t4", + "provider_id": "p1", + "name": "Std Ship A", + "features": { + "cost": 5.0, + "time": 500, + "reliability": 0.95, + "reputation": 8.0 + } + }, + { + "id": "c4_2", + "task_id": "t4", + "provider_id": "p1", + "name": "Std Ship B", + "features": { + "cost": 4.0, + "time": 600, + "reliability": 0.90, + "reputation": 7.0 + } + }, + { + "id": "c4_3", + "task_id": "t4", + "provider_id": "p1", + "name": "Std Ship C", + "features": { + "cost": 6.0, + "time": 450, + "reliability": 0.98, + "reputation": 9.0 + } + }, + { + "id": "c5_1", + "task_id": "t5", + "provider_id": "p1", + "name": "Exp Ship A", + "features": { + "cost": 10.0, + "time": 100, + "reliability": 0.99, + "reputation": 9.5 + } + }, + { + "id": "c5_2", + "task_id": "t5", + "provider_id": "p1", + "name": "Exp Ship B", + "features": { + "cost": 12.0, + "time": 80, + "reliability": 0.999, + "reputation": 9.8 + } + }, + { + "id": "c5_3", + "task_id": "t5", + "provider_id": "p1", + "name": "Exp Ship C", + "features": { + "cost": 8.0, + "time": 120, + "reliability": 0.95, + "reputation": 8.5 + } + }, + { + "id": "c6_1", + "task_id": "t6", + "provider_id": "p1", + "name": "Payment A", + "features": { + "cost": 2.5, + "time": 300, + "reliability": 0.999, + "reputation": 9.0 + } + }, + { + "id": "c6_2", + "task_id": "t6", + "provider_id": "p1", + "name": "Payment B", + "features": { + "cost": 1.5, + "time": 500, + "reliability": 0.95, + "reputation": 7.0 + } + }, + { + "id": "c6_3", + "task_id": "t6", + "provider_id": "p1", + "name": "Payment C", + "features": { + "cost": 3.0, + "time": 200, + "reliability": 0.99, + "reputation": 9.5 + } + }, + { + "id": "c7_1", + "task_id": "t7", + "provider_id": "p1", + "name": "Email A", + "features": { + "cost": 0.01, + "time": 10, + "reliability": 0.99, + "reputation": 9.0 + } + }, + { + "id": "c7_2", + "task_id": "t7", + "provider_id": "p1", + "name": "Email B", + "features": { + "cost": 0.005, + "time": 20, + "reliability": 0.95, + "reputation": 8.0 + } + }, + { + "id": "c7_3", + "task_id": "t7", + "provider_id": "p1", + "name": "Email C", + "features": { + "cost": 0.001, + "time": 50, + "reliability": 0.90, + "reputation": 7.0 + } + }, + { + "id": "c8_1", + "task_id": "t8", + "provider_id": "p1", + "name": "SMS A", + "features": { + "cost": 0.1, + "time": 5, + "reliability": 0.999, + "reputation": 9.8 + } + }, + { + "id": "c8_2", + "task_id": "t8", + "provider_id": "p1", + "name": "SMS B", + "features": { + "cost": 0.05, + "time": 10, + "reliability": 0.98, + "reputation": 9.0 + } + }, + { + "id": "c8_3", + "task_id": "t8", + "provider_id": "p1", + "name": "SMS C", + "features": { + "cost": 0.02, + "time": 20, + "reliability": 0.95, + "reputation": 8.5 + } + }, + { + "id": "c9_1", + "task_id": "t9", + "provider_id": "p1", + "name": "CRM A", + "features": { + "cost": 0.5, + "time": 100, + "reliability": 0.99, + "reputation": 9.0 + } + }, + { + "id": "c9_2", + "task_id": "t9", + "provider_id": "p1", + "name": "CRM B", + "features": { + "cost": 0.3, + "time": 200, + "reliability": 0.95, + "reputation": 8.0 + } + }, + { + "id": "c9_3", + "task_id": "t9", + "provider_id": "p1", + "name": "CRM C", + "features": { + "cost": 0.1, + "time": 400, + "reliability": 0.90, + "reputation": 7.0 + } + }, + { + "id": "c10_1", + "task_id": "t10", + "provider_id": "p1", + "name": "Logs A", + "features": { + "cost": 0.2, + "time": 50, + "reliability": 0.99, + "reputation": 9.0 + } + }, + { + "id": "c10_2", + "task_id": "t10", + "provider_id": "p1", + "name": "Logs B", + "features": { + "cost": 0.1, + "time": 60, + "reliability": 0.98, + "reputation": 8.5 + } + }, + { + "id": "c10_3", + "task_id": "t10", + "provider_id": "p1", + "name": "Logs C", + "features": { + "cost": 0.05, + "time": 80, + "reliability": 0.95, + "reputation": 8.0 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "root_seq", + "kind": "SEQ", + "children": [ + {"id": "n1", "kind": "TASK", "task_id": "t1"}, + { + "id": "parallel_check", + "kind": "AND", + "children": [ + { + "id": "n2", + "kind": "TASK", + "task_id": "t2" + }, + { + "id": "n3", + "kind": "TASK", + "task_id": "t3" + } + ] + }, + { + "id": "shipping_choice", + "kind": "XOR", + "branches": [ + { + "child": { + "id": "n4", + "kind": "TASK", + "task_id": "t4" + }, + "p": 0.8 + }, + { + "child": { + "id": "n5", + "kind": "TASK", + "task_id": "t5" + }, + "p": 0.2 + } + ] + }, + { + "id": "payment_retry_loop", + "kind": "LOOP", + "body": { + "id": "n6", + "kind": "TASK", + "task_id": "t6" + }, + "expected_iterations": 1.1 + }, + { + "id": "notification_seq", + "kind": "SEQ", + "children": [ + { + "id": "n7", + "kind": "TASK", + "task_id": "t7" + }, + { + "id": "n8", + "kind": "TASK", + "task_id": "t8" + } + ] + }, + {"id": "n9", "kind": "TASK", "task_id": "t9"}, + {"id": "n10", "kind": "TASK", "task_id": "t10"} + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "xor": { + "fn": "SCALED_SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "time": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "xor": { + "fn": "SCALED_SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "reliability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "reputation": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "xor": { + "fn": "SCALED_SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "cost", + "time", + "reliability", + "reputation" + ], + "weights": { + "cost": 0.4, + "time": 0.3, + "reliability": 0.2, + "reputation": 0.1 + } + } +} diff --git a/examples/demo/11_multi_obj_negative.json b/examples/demo/11_multi_obj_negative.json new file mode 100644 index 0000000..55cb8cd --- /dev/null +++ b/examples/demo/11_multi_obj_negative.json @@ -0,0 +1,49 @@ +{ + "metadata": { + "id": "demo-multi-obj", + "name": "Multi-Objective Demo (2 Objectives)", + "version": "1.0.0", + "created_at": "2026-02-10T12:00:00Z", + "description": "A demo instance with 2 objectives, which should be rejected by all engines as per current configuration (Multi=2..3 is negative test).", + "level": "expert" + }, + "providers": [ + { "id": "P1", "name": "Provider 1" } + ], + "tasks": [ + { "id": "T1", "name": "Task 1" }, + { "id": "T2", "name": "Task 2" } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "root", + "kind": "SEQ", + "children": [ + { "id": "n1", "kind": "TASK", "task_id": "T1" }, + { "id": "n2", "kind": "TASK", "task_id": "T2" } + ] + } + }, + "candidates": [ + { "id": "S1_1", "task_id": "T1", "provider_id": "P1", "name": "T1 Service 1", "features": { "cost": 10, "time": 5, "reliability": 0.99 } }, + { "id": "S1_2", "task_id": "T1", "provider_id": "P1", "name": "T1 Service 2", "features": { "cost": 20, "time": 2, "reliability": 0.95 } }, + { "id": "S2_1", "task_id": "T2", "provider_id": "P1", "name": "T2 Service 1", "features": { "cost": 15, "time": 4, "reliability": 0.98 } }, + { "id": "S2_2", "task_id": "T2", "provider_id": "P1", "name": "T2 Service 2", "features": { "cost": 25, "time": 1, "reliability": 0.90 } } + ], + "features": [ + { "id": "cost", "name": "Cost", "direction": "MINIMIZE", "unit": "eur", "scale": "RATIO", "valid_range": { "min": 0, "max": 100 } }, + { "id": "time", "name": "Time", "direction": "MINIMIZE", "unit": "s", "scale": "RATIO", "valid_range": { "min": 0, "max": 100 } }, + { "id": "reliability", "name": "Reliability", "direction": "MAXIMIZE", "unit": "p", "scale": "RATIO", "valid_range": { "min": 0, "max": 1 } } + ], + "aggregation_policies": { + "cost": { "neutral": 0, "compose": { "seq": { "fn": "SUM" }, "and": { "fn": "SUM" }, "loop": { "fn": "SCALED_SUM" } } }, + "time": { "neutral": 0, "compose": { "seq": { "fn": "SUM" }, "and": { "fn": "SUM" }, "loop": { "fn": "SCALED_SUM" } } }, + "reliability": { "neutral": 1, "compose": { "seq": { "fn": "PRODUCT" }, "and": { "fn": "PRODUCT" }, "loop": { "fn": "SCALED_PRODUCT" } } } + }, + "objective": { + "type": "MULTI", + "targets": ["cost", "time"], + "weights": { "cost": 0.5, "time": 0.5 } + } +} diff --git a/examples/demo/12_many_obj_pareto.json b/examples/demo/12_many_obj_pareto.json new file mode 100644 index 0000000..0565a1a --- /dev/null +++ b/examples/demo/12_many_obj_pareto.json @@ -0,0 +1,59 @@ +{ + "metadata": { + "id": "demo-many-obj", + "name": "Many-Objective Demo (3 Objectives)", + "version": "1.0.0", + "created_at": "2026-02-10T12:00:00Z", + "description": "A demo instance with 3 objectives, designed for the Many-Heuristic engine to find a Pareto front.", + "level": "expert" + }, + "providers": [ + { "id": "P1", "name": "Provider 1" } + ], + "tasks": [ + { "id": "T1", "name": "Task 1" }, + { "id": "T2", "name": "Task 2" }, + { "id": "T3", "name": "Task 3" } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "root", + "kind": "SEQ", + "children": [ + { "id": "n1", "kind": "TASK", "task_id": "T1" }, + { "id": "n2", "kind": "TASK", "task_id": "T2" }, + { "id": "n3", "kind": "TASK", "task_id": "T3" } + ] + } + }, + "candidates": [ + { "id": "S1_1", "task_id": "T1", "provider_id": "P1", "name": "T1 Service 1", "features": { "cost": 10, "time": 5, "reliability": 0.99 } }, + { "id": "S1_2", "task_id": "T1", "provider_id": "P1", "name": "T1 Service 2", "features": { "cost": 50, "time": 1, "reliability": 0.999 } }, + + { "id": "S2_1", "task_id": "T2", "provider_id": "P1", "name": "T2 Service 1", "features": { "cost": 20, "time": 4, "reliability": 0.95 } }, + { "id": "S2_2", "task_id": "T2", "provider_id": "P1", "name": "T2 Service 2", "features": { "cost": 5, "time": 10, "reliability": 0.80 } }, + + { "id": "S3_1", "task_id": "T3", "provider_id": "P1", "name": "T3 Service 1", "features": { "cost": 15, "time": 3, "reliability": 0.90 } }, + { "id": "S3_2", "task_id": "T3", "provider_id": "P1", "name": "T3 Service 2", "features": { "cost": 30, "time": 2, "reliability": 0.95 } } + ], + "features": [ + { "id": "cost", "name": "Cost", "direction": "MINIMIZE", "unit": "eur", "scale": "RATIO", "valid_range": { "min": 0, "max": 100 } }, + { "id": "time", "name": "Time", "direction": "MINIMIZE", "unit": "s", "scale": "RATIO", "valid_range": { "min": 0, "max": 100 } }, + { "id": "reliability", "name": "Reliability", "direction": "MAXIMIZE", "unit": "p", "scale": "RATIO", "valid_range": { "min": 0.0, "max": 1.0 } } + ], + "aggregation_policies": { + "cost": { "neutral": 0, "compose": { "seq": { "fn": "SUM" }, "and": { "fn": "SUM" }, "loop": { "fn": "SCALED_SUM" } } }, + "time": { "neutral": 0, "compose": { "seq": { "fn": "SUM" }, "and": { "fn": "SUM" }, "loop": { "fn": "SCALED_SUM" } } }, + "reliability": { "neutral": 1, "compose": { "seq": { "fn": "PRODUCT" }, "and": { "fn": "PRODUCT" }, "loop": { "fn": "SCALED_PRODUCT" } } } + }, + "objective": { + "type": "MANY", + "targets": ["cost", "time", "reliability"], + "weights": { + "cost": 0.34, + "time": 0.33, + "reliability": 0.33 + } + } +} diff --git a/examples/demo/README.md b/examples/demo/README.md new file mode 100644 index 0000000..4b7292c --- /dev/null +++ b/examples/demo/README.md @@ -0,0 +1,72 @@ +# OpenBinding Demo Examples + +This directory contains a set of 12 diverse composition problems designed to demonstrate the various features and capabilities of the OpenBinding framework, including different composition structures, constraints, and objectives. + +## Core Concepts (JSON Model) + +Each example is a JSON file that defines a service composition problem. The key components are: + +* **`metadata`**: General information about the problem (ID, name, description). +* **`features`**: The Quality of Service (QoS) attributes to be optimized or constrained (e.g., Latency, Cost, Availability). + * Defines `direction` (minimize/maximize), `unit`, `scale`, and `valid_range`. +* **`providers`**: The entities offering services. +* **`tasks`**: The abstract steps in the workflow that need to be performed. +* **`candidates`**: Concrete service implementations available for each task. Each candidate has specific `features` values. +* **`composition`**: The structural definition of the workflow. + * **`SEQ`**: Sequential execution. + * **`AND`**: Parallel execution. + * **`XOR`**: Conditional branching (probabilistic). + * **`LOOP`**: Repeated execution. +* **`aggregation_policies`**: Rules for how feature values are aggregated across the composition structure (e.g., Sum of costs, Max of latencies). +* **`constraints`**: Restrictions on valid solutions. + * **`ATTRIBUTE_BOUND`**: Limits on QoS values (Global or Local). + * **`DEPENDENCY`**: Constraints between providers (e.g., `SAME_PROVIDER` for two tasks). +* **`objective`**: The goal of the optimization. + * **`MONO`**: Optimize one feature (or a weighted sum of multiple features). + * **`MULTI`**: Optimize multiple features (Negative test for now). + * **`MANY`**: Optimize many features (3+) for Pareto Front. + +## Example Guide + +Here is a guide to the included examples and their specific intent: + +| File | Intent / Key Feature | Description | +| :--- | :--- | :--- | +| **`01_simple_seq.json`** | **Basic Sequence** | A minimal example of a sequential workflow. Good for verifying basic connectivity and solving. | +| **`02_parallel.json`** | **Parallel Flow (AND)** | Demonstrates parallel execution. Shows how `MAX` aggregation (for latency) works differently from `SUM`. | +| **`03_xor_choice.json`** | **Probabilistic Branching (XOR)** | Uses `XOR` nodes with probabilities. The objective is expected availability. | +| **`04_conflict.json`** | **Infeasibility** | A problem designed to be unsolvable due to conflicting constraints. Use this to test error handling or "No Solution" responses. | +| **`05_multi_obj.json`** | **Weighted Sum (MONO)** | A Cost+Latency trade-off encoded as a `MONO` weighted-sum objective (supported by current engines). | +| **`06_loops.json`** | **Loops** | Demonstrates the `LOOP` structure. Aggregation uses `expected_iterations` to estimate QoS. | +| **`07_soft_constraints.json`** | **Soft Constraints** | Includes a constraint marked `hard: false`. Violations should be penalized but allowed. | +| **`08_dependencies.json`** | **Provider Dependencies** | Forces two independent tasks to select services from the `SAME_PROVIDER`. | +| **`09_mixed.json`** | **Complex/Mixed** | Combines multiple structures (Seq, XOR) and constraints. A more realistic scenario. | +| **`10_large_scale.json`** | **Scale/Performance** | A larger composition (10 sequential tasks) with more candidates, used to test solver performance. | +| **`11_multi_obj_negative.json`** | **Multi-Objective (Negative)** | A problem with 2 objectives. Used to verify that engines correctly reject "Multi" objectives (at the moment there are no engines that support this type of objective). | +| **`12_many_obj_pareto.json`** | **Many-Objective (Pareto)** | A problem with 3 objectives. The **Many-Heuristic** engine should return a set of Pareto-optimal solutions for this input. | + +## Usage + +You can send these examples to the OpenBinding Gateway using `curl`. + +**Prerequisite**: Ensure the gateway is running at `http://localhost:8000`. + +### Example Command + +To solve the **Simple Sequence** example using the **Random Search** engine: + +```bash +curl -X POST "http://localhost:8000/v1/solve" \ + -H "Content-Type: application/json" \ + -d @<(jq -n --argfile inst 01_simple_seq.json '{engine_id:"random-search", instance:$inst, options:{iterations_count:1000}, verbose:false}') +``` + +To solve the **Many-Objective** example using the **Many-Heuristic** engine: + +```bash +curl -X POST "http://localhost:8000/v1/solve" \ + -H "Content-Type: application/json" \ + -d @<(jq -n --argfile inst 12_many_obj_pareto.json '{engine_id:"many-heuristic", instance:$inst, options:{iterations_count:1000, archive_size:20}, verbose:false}') +``` + +**Note**: Ensure you are in the `examples/demo` directory when running these commands, or provide the full path to the JSON file. diff --git a/examples/literature/README.md b/examples/literature/README.md new file mode 100644 index 0000000..90b9bfa --- /dev/null +++ b/examples/literature/README.md @@ -0,0 +1,58 @@ +# Literature Scenarios + +This directory contains problem instances derived from academic literature in the field of QoS-aware Web Service Composition. The selection of these scenarios is guided by the literature analysis and characterization reported in **Pesl et al.**, *Uncovering LLMs for Service-Composition: Challenges and Opportunities*, which identifies them as representative examples for the area. + +## Sources + +The instances are adapted from the following key papers and datasets: + +* **Pesl et al.**: *Uncovering LLMs for Service-Composition: Challenges and Opportunities*. + * **DOI**: [10.1007/978-981-97-0989-2_4](https://doi.org/10.1007/978-981-97-0989-2_4) + * **Authors**: Robin D. Pesl, Miles Stötzner, Ilche Georgievski & Marco Aiello. + * **Note**: This work reviews the service-composition literature and highlights these scenarios as representative examples used across prior research. + +* **Benatallah et al. (2002)**: *Declarative Composition and Peer-to-Peer Provisioning of Dynamic Web Services*. + * **DOI**: [10.1109/ICDE.2002.994701](https://doi.org/10.1109/ICDE.2002.994701) + * **Source**: Derived from the "Travel Solution" motivating example (CTS and ITAS statecharts). + +* **Bultan et al. (2003)**: *Conversation Specification: A New Approach to Design and Analysis of Web Service Composition*. + * **DOI**: [10.1145/775152.775210](https://doi.org/10.1145/775152.775210) + * **Source**: E-commerce purchase workflow. + +* **Cremaschi et al. (2018)**: *A Practical Approach to Services Composition Through Light Semantic Descriptions*. + * **DOI**: [10.1007/978-3-319-99819-0_10](https://doi.org/10.1007/978-3-319-99819-0_10) + * **Source**: A healthcare workflow involving patient monitoring and emergency response. + +* **Netedu et al. (2020)**: *A Web Service Composition Method Based on OpenAPI Semantic Annotations*. + * **DOI**: [10.1007/978-3-030-34986-8_25](https://doi.org/10.1007/978-3-030-34986-8_25) + * **Source**: Transport Agency case study. + +* **Pautasso (2009)**: *RESTful Web service composition with BPEL for REST*. + * **DOI**: [10.1016/j.datak.2009.02.016](https://doi.org/10.1016/j.datak.2009.02.016) + * **Source**: E-commerce scenario. + +* **Zeng et al. (2004)**: *QoS-Aware Middleware for Web Services Composition*. + * **DOI**: [10.1109/TSE.2004.11](https://doi.org/10.1109/TSE.2004.11) + * **Source**: One of the seminal papers introducing global optimization for service composition. + +* **Zhang et al. (2014)**: *Context-aware Generic Service Discovery and Service Composition*. + * **DOI**: [10.1109/MobServ.2014.27](https://doi.org/10.1109/MobServ.2014.27) + * **Source**: Personal Entertainment Planner. + +## Structure + +Each JSON file represents a "Base Scenario". These base scenarios define the *structure* (Tasks, Composition) and *features* of the problem. + +For experimentation, these base scenarios are typically **scaled up** using the `experimentation/generator.py` script, which: +1. Multiplies the number of candidates per task to increase the binding space size. +2. Varies the constraints and objectives to create diverse test instances. + +## Usage + +To use a base scenario directly: + +```bash +curl -X POST "http://localhost:8000/v1/solve?engine=random-search" \ + -H "Content-Type: application/json" \ + -d @benatallah.json +``` diff --git a/examples/literature/benatallah.json b/examples/literature/benatallah.json new file mode 100644 index 0000000..b09d151 --- /dev/null +++ b/examples/literature/benatallah.json @@ -0,0 +1,399 @@ +{ + "metadata": { + "id": "benatallah2002-selfserv-travel-solution-cts-itas", + "name": "Travel Solution (Benatallah et al. 2002)", + "version": "1.0.0", + "created_at": "2026-02-02T12:00:00Z", + "description": "Problem instance derived from the SELF-SERV running example (CTS and ITAS statecharts). QoS values and branch probabilities are illustrative because the paper does not provide numeric QoS.", + "paper": { + "title": "Declarative Compositionand Peer-to-PeerProvisioning of Dynamic WebServices", + "authors": "B. Benatallah et al.", + "year": 2002, + "doi": "10.5555/876875.878987" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Total price charged to customer", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "availability", + "name": "Probability the service invocation succeeds", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + } + ], + "providers": [ + { + "id": "p_attractions_a", + "name": "AttractionsSearch Provider A" + }, + { + "id": "p_attractions_b", + "name": "AttractionsSearch Provider B" + }, + { + "id": "p_dom_air_a", + "name": "Domestic Airline A" + }, + { + "id": "p_dom_air_b", + "name": "Domestic Airline B" + }, + { + "id": "p_int_air_a", + "name": "International Airline A" + }, + { + "id": "p_int_air_b", + "name": "International Airline B" + }, + { + "id": "p_ins_a", + "name": "Travel Insurance Co. A" + }, + { + "id": "p_ins_b", + "name": "Travel Insurance Co. B" + }, + { + "id": "p_hotel_a", + "name": "Accommodation Provider A" + }, + { + "id": "p_hotel_b", + "name": "Accommodation Provider B" + }, + { + "id": "p_car_a", + "name": "Car Rental Provider A" + }, + { + "id": "p_car_b", + "name": "Car Rental Provider B" + } + ], + "tasks": [ + { + "id": "t_attractions_search", + "name": "Attractions Search (ASS.getAttractions)" + }, + { + "id": "t_flight_booking_domestic", + "name": "Domestic Flight Booking (DFBS.booking)" + }, + { + "id": "t_flight_booking_international", + "name": "International Flight Booking (IFBS.booking)" + }, + { + "id": "t_travel_insurance", + "name": "Travel Insurance (TIS.getInsurance)" + }, + { + "id": "t_accommodation_booking", + "name": "Accommodation Booking (ABS.booking)" + }, + { + "id": "t_car_rental_booking", + "name": "Car Rental Booking (CRS.booking)" + } + ], + "candidates": [ + { + "id": "svc_ass_1", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_a", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 180, + "cost_usd": 0, + "availability": 0.995 + } + }, + { + "id": "svc_ass_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 120, + "cost_usd": 5, + "availability": 0.99 + } + }, + { + "id": "svc_dfbs_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_a", + "name": "DFBS.booking", + "features": { + "latency_ms": 650, + "cost_usd": 420, + "availability": 0.985 + } + }, + { + "id": "svc_dfbs_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_b", + "name": "DFBS.booking", + "features": { + "latency_ms": 520, + "cost_usd": 460, + "availability": 0.99 + } + }, + { + "id": "svc_ifbs_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking", + "features": { + "latency_ms": 780, + "cost_usd": 820, + "availability": 0.98 + } + }, + { + "id": "svc_ifbs_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_b", + "name": "IFBS.booking", + "features": { + "latency_ms": 610, + "cost_usd": 900, + "availability": 0.988 + } + }, + { + "id": "svc_tis_1", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 240, + "cost_usd": 55, + "availability": 0.997 + } + }, + { + "id": "svc_tis_2", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 190, + "cost_usd": 70, + "availability": 0.999 + } + }, + { + "id": "svc_abs_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_a", + "name": "ABS.booking", + "features": { + "latency_ms": 430, + "cost_usd": 950, + "availability": 0.992 + } + }, + { + "id": "svc_abs_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_b", + "name": "ABS.booking", + "features": { + "latency_ms": 350, + "cost_usd": 1100, + "availability": 0.995 + } + }, + { + "id": "svc_crs_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_a", + "name": "CRS.booking", + "features": { + "latency_ms": 310, + "cost_usd": 260, + "availability": 0.99 + } + }, + { + "id": "svc_crs_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_b", + "name": "CRS.booking", + "features": { + "latency_ms": 260, + "cost_usd": 320, + "availability": 0.996 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_parallel", + "kind": "AND", + "children": [ + { + "id": "n_as", + "kind": "TASK", + "task_id": "t_attractions_search" + }, + { + "id": "n_booking_flow", + "kind": "SEQ", + "children": [ + { + "id": "n_flight_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.6, + "child": { + "id": "n_dfb", + "kind": "TASK", + "task_id": "t_flight_booking_domestic" + } + }, + { + "p": 0.4, + "child": { + "id": "n_intl_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_ifb", + "kind": "TASK", + "task_id": "t_flight_booking_international" + }, + { + "id": "n_ti", + "kind": "TASK", + "task_id": "t_travel_insurance" + } + ] + } + } + ] + }, + { + "id": "n_ab", + "kind": "TASK", + "task_id": "t_accommodation_booking" + } + ] + } + ] + }, + { + "id": "n_car_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.3, + "child": { + "id": "n_cr", + "kind": "TASK", + "task_id": "t_car_rental_booking" + } + }, + { + "p": 0.7, + "child": { + "id": "n_no_car", + "kind": "ELEMENT", + "description": "Skip car rental (represents the near(...) branch)" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": ["latency_ms", "cost_usd", "availability"], + "weights": { + "latency_ms": 0.3, + "cost_usd": 0.4, + "availability": 0.3 + } + } +} diff --git a/examples/literature/bultan.json b/examples/literature/bultan.json new file mode 100644 index 0000000..d45b89a --- /dev/null +++ b/examples/literature/bultan.json @@ -0,0 +1,237 @@ +{ + "metadata": { + "id": "bultan2003-warehouse-example", + "name": "Warehouse Composition example (Bultan et al. 2003)", + "version": "1.0.0", + "created_at": "2026-02-02T00:00:00Z", + "description": "Problem instance derived from Example 2.1 and Example 3.1 (store-bank-warehouse) in Bultan et al., WWW'03.", + "paper": { + "title": "Conversation Specification: A New Approach to Design and Analysis of E-Service Composition", + "authors": "T. Bultan et al.", + "year": 2003, + "doi": "10.1145/775152.775210" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 5000 } + }, + { + "id": "cost_usd", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 1000 } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 1 } + } + ], + "providers": [ + { "id": "p_store", "name": "Store" }, + { "id": "p_bank", "name": "Bank" }, + { "id": "p_wh1", "name": "Warehouse1" }, + { "id": "p_wh2", "name": "Warehouse2" } + ], + "tasks": [ + { "id": "t_authorize", "name": "Send authorize (store→bank)" }, + { "id": "t_ok", "name": "Send ok (bank→store)" }, + { "id": "t_order1", "name": "Send order1 (store→warehouse1)" }, + { "id": "t_receipt1", "name": "Send receipt1 (warehouse1→store)" }, + { "id": "t_bill1", "name": "Send bill1 (warehouse1→bank)" }, + { "id": "t_payment1", "name": "Send payment1 (bank→warehouse1)" }, + { "id": "t_order2", "name": "Send order2 (store→warehouse2)" }, + { "id": "t_receipt2", "name": "Send receipt2 (warehouse2→store)" }, + { "id": "t_bill2", "name": "Send bill2 (warehouse2→bank)" }, + { "id": "t_payment2", "name": "Send payment2 (bank→warehouse2)" } + ], + "candidates": [ + { + "id": "c_authorize_store_v1", + "task_id": "t_authorize", + "provider_id": "p_store", + "name": "authorize", + "features": { "latency_ms": 55, "cost_usd": 0.01, "availability": 0.999 } + }, + { + "id": "c_ok_bank_v1", + "task_id": "t_ok", + "provider_id": "p_bank", + "name": "ok", + "features": { "latency_ms": 45, "cost_usd": 0.01, "availability": 0.999 } + }, + { + "id": "c_order1_store_v1", + "task_id": "t_order1", + "provider_id": "p_store", + "name": "order1", + "features": { "latency_ms": 65, "cost_usd": 0.02, "availability": 0.998 } + }, + { + "id": "c_receipt1_wh1_v1", + "task_id": "t_receipt1", + "provider_id": "p_wh1", + "name": "receipt1", + "features": { "latency_ms": 80, "cost_usd": 0.015, "availability": 0.997 } + }, + { + "id": "c_bill1_wh1_v1", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1", + "features": { "latency_ms": 75, "cost_usd": 0.015, "availability": 0.998 } + }, + { + "id": "c_payment1_bank_v1", + "task_id": "t_payment1", + "provider_id": "p_bank", + "name": "payment1", + "features": { "latency_ms": 90, "cost_usd": 0.03, "availability": 0.999 } + }, + { + "id": "c_order2_store_v1", + "task_id": "t_order2", + "provider_id": "p_store", + "name": "order2", + "features": { "latency_ms": 70, "cost_usd": 0.02, "availability": 0.998 } + }, + { + "id": "c_receipt2_wh2_v1", + "task_id": "t_receipt2", + "provider_id": "p_wh2", + "name": "receipt2", + "features": { "latency_ms": 85, "cost_usd": 0.015, "availability": 0.997 } + }, + { + "id": "c_bill2_wh2_v1", + "task_id": "t_bill2", + "provider_id": "p_wh2", + "name": "bill2", + "features": { "latency_ms": 78, "cost_usd": 0.015, "availability": 0.998 } + }, + { + "id": "c_payment2_bank_v1", + "task_id": "t_payment2", + "provider_id": "p_bank", + "name": "payment2", + "features": { "latency_ms": 95, "cost_usd": 0.03, "availability": 0.999 } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { "id": "n_authorize", "kind": "TASK", "task_id": "t_authorize" }, + { "id": "n_ok", "kind": "TASK", "task_id": "t_ok" }, + { + "id": "n_parallel_orders", + "kind": "AND", + "children": [ + { + "id": "n_loop_wh1", + "kind": "LOOP", + "bounds": { "min": 0, "max": 5 }, + "body": { + "id": "n_wh1_iter_seq", + "kind": "SEQ", + "children": [ + { "id": "n_order1", "kind": "TASK", "task_id": "t_order1" }, + { + "id": "n_wh1_after_order", + "kind": "AND", + "children": [ + { "id": "n_receipt1", "kind": "TASK", "task_id": "t_receipt1" }, + { + "id": "n_wh1_billpay", + "kind": "SEQ", + "children": [ + { "id": "n_bill1", "kind": "TASK", "task_id": "t_bill1" }, + { "id": "n_payment1", "kind": "TASK", "task_id": "t_payment1" } + ] + } + ] + } + ] + } + }, + { + "id": "n_loop_wh2", + "kind": "LOOP", + "bounds": { "min": 0, "max": 5 }, + "body": { + "id": "n_wh2_iter_seq", + "kind": "SEQ", + "children": [ + { "id": "n_order2", "kind": "TASK", "task_id": "t_order2" }, + { + "id": "n_wh2_after_order", + "kind": "AND", + "children": [ + { "id": "n_receipt2", "kind": "TASK", "task_id": "t_receipt2" }, + { + "id": "n_wh2_billpay", + "kind": "SEQ", + "children": [ + { "id": "n_bill2", "kind": "TASK", "task_id": "t_bill2" }, + { "id": "n_payment2", "kind": "TASK", "task_id": "t_payment2" } + ] + } + ] + } + ] + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { "fn": "SUM" }, + "and": { "fn": "MAX" }, + "loop": { "fn": "SCALED_SUM" } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { "fn": "SUM" }, + "and": { "fn": "SUM" }, + "loop": { "fn": "SCALED_SUM" } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { "fn": "PRODUCT" }, + "and": { "fn": "PRODUCT" }, + "loop": { "fn": "SCALED_PRODUCT" } + } + } + }, + "objective": { + "type": "MONO", + "targets": ["latency_ms", "cost_usd", "availability"], + "weights": { + "latency_ms": 0.5, + "cost_usd": 0.3, + "availability": 0.2 + } + } +} diff --git a/examples/literature/cremaschi.json b/examples/literature/cremaschi.json new file mode 100644 index 0000000..2cde3eb --- /dev/null +++ b/examples/literature/cremaschi.json @@ -0,0 +1,202 @@ +{ + "metadata": { + "id": "cremaschi2018-textbook-access", + "name": "Book info retrieval (Cremaschi et al. 2018)", + "version": "1.0.0", + "created_at": "2026-02-02T00:00:00Z", + "description": "QoS-aware instance derived from the running example in 'A Practical Approach to Services Composition Through Light Semantic Descriptions' (ESOCC 2018). QoS values are illustrative placeholders.", + "paper": { + "title": "A Practical Approach to Services Composition Through Light Semantic Descriptions", + "authors": "M. Cremaschi et al.", + "year": 2018, + "doi": "10.1007/978-3-319-99819-0_10" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 10000 } + }, + { + "id": "cost_usd", + "name": "Monetary cost per execution", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 10 } + }, + { + "id": "availability", + "name": "Service availability", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 1 } + } + ], + "providers": [ + { + "id": "p_google", + "name": "Google" + }, + { + "id": "p_amazon", + "name": "Amazon" + }, + { + "id": "p_unimib", + "name": "University of Milan - Bicocca (OPAC library)" + }, + { + "id": "p_archive", + "name": "Archive.org" + }, + { + "id": "p_local", + "name": "Local Application" + } + ], + "tasks": [ + { "id": "t_books", "name": "Retrieve book metadata from title (ISBN/author/title)" }, + { "id": "t_market", "name": "Check e-commerce availability/price by ISBN" }, + { "id": "t_library", "name": "Check library availability and retrieve library address" }, + { "id": "t_geocoding", "name": "Geocode library address into coordinates" }, + { "id": "t_transit", "name": "Retrieve public transport options to the library" }, + { "id": "t_archive", "name": "Check free eBook availability (Archive.org)" } + ], + "candidates": [ + { + "id": "c_google_books_api", + "task_id": "t_books", + "provider_id": "p_google", + "name": "Google Books API", + "features": { + "latency_ms": 250, + "cost_usd": 0.0001, + "availability": 0.995 + } + }, + { + "id": "c_amazon_market_api", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API", + "features": { + "latency_ms": 400, + "cost_usd": 0.0010, + "availability": 0.990 + } + }, + { + "id": "c_opac_library_api", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API", + "features": { + "latency_ms": 350, + "cost_usd": 0.0001, + "availability": 0.980 + } + }, + { + "id": "c_google_geocoding_api", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API", + "features": { + "latency_ms": 300, + "cost_usd": 0.0020, + "availability": 0.995 + } + }, + { + "id": "c_google_transit_api", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API", + "features": { + "latency_ms": 450, + "cost_usd": 0.0001, + "availability": 0.995 + } + }, + { + "id": "c_archive_api", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API", + "features": { + "latency_ms": 500, + "cost_usd": 0.0001, + "availability": 0.970 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { "id": "n_books", "kind": "TASK", "task_id": "t_books" }, + { + "id": "n_parallel_options", + "kind": "AND", + "children": [ + { "id": "n_amazon", "kind": "TASK", "task_id": "t_market" }, + { + "id": "n_library_trip", + "kind": "SEQ", + "children": [ + { "id": "n_opac", "kind": "TASK", "task_id": "t_library" }, + { "id": "n_geocode", "kind": "TASK", "task_id": "t_geocoding" }, + { "id": "n_transit", "kind": "TASK", "task_id": "t_transit" } + ] + }, + { "id": "n_archive", "kind": "TASK", "task_id": "t_archive" } + ] + }, + { "id": "n_report", "kind": "ELEMENT", "description": "Assemble final textbook access report"} + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { "fn": "SUM" }, + "and": { "fn": "MAX" }, + "loop": { "fn": "SCALED_SUM" } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { "fn": "SUM" }, + "and": { "fn": "SUM" }, + "loop": { "fn": "SCALED_SUM" } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { "fn": "PRODUCT" }, + "and": { "fn": "PRODUCT" }, + "loop": { "fn": "SCALED_PRODUCT" } + } + } + }, + "objective": { + "type": "MONO", + "targets": ["latency_ms", "cost_usd", "availability"], + "weights": { + "availability": 0.4, + "latency_ms": 0.3, + "cost_usd": 0.3 + } + } +} diff --git a/examples/literature/netedu.json b/examples/literature/netedu.json new file mode 100644 index 0000000..d64dc97 --- /dev/null +++ b/examples/literature/netedu.json @@ -0,0 +1,113 @@ +{ + "metadata": { + "id": "netedu2020-transport-agency", + "name": "Transport Agency case study (Netedu et al. 2020)", + "version": "1.0.0", + "created_at": "2026-02-02T12:00:00Z", + "description": "Models the running example from 'A Web Service Composition Method Based on OpenAPI Semantic Annotations' (Netedu et al., 2020), Sect. 5 Case Study: A Transport Agency. QoS values are not provided in the paper; a minimal 'cost' feature is added for schema compliance.", + "paper": { + "title": "A Web Service Composition Method Based on OpenAPI Semantic Annotations", + "authors": "A. Netedu et al.", + "year": 2020, + "doi": "10.1007/978-3-030-34986-8_25" + } + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "USD", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 1000 } + } + ], + "providers": [ + { + "id": "p_transport_agency", + "name": "Transport Agency REST API" + } + ], + "tasks": [ + { "id": "t_get_country_from_location", "name": "getCountryFromLocation" }, + { "id": "t_get_transport_company", "name": "getTransportCompany" }, + { "id": "t_get_closest_city", "name": "getClosestCity" }, + { "id": "t_get_local_subsidiary", "name": "getLocalSubsidiary" }, + { "id": "t_get_vehicle", "name": "getVehicle" }, + { "id": "t_make_arrangements", "name": "makeArrangements" } + ], + "candidates": [ + { + "id": "c_get_country_from_location", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation", + "features": { "cost": 1 } + }, + { + "id": "c_get_transport_company", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany", + "features": { "cost": 1 } + }, + { + "id": "c_get_closest_city", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity", + "features": { "cost": 1 } + }, + { + "id": "c_get_local_subsidiary", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary", + "features": { "cost": 1 } + }, + { + "id": "c_get_vehicle", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle", + "features": { "cost": 1 } + }, + { + "id": "c_make_arrangements", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements", + "features": { "cost": 1 } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { "id": "n_country", "kind": "TASK", "task_id": "t_get_country_from_location" }, + { "id": "n_company", "kind": "TASK", "task_id": "t_get_transport_company" }, + { "id": "n_city", "kind": "TASK", "task_id": "t_get_closest_city" }, + { "id": "n_subsidiary", "kind": "TASK", "task_id": "t_get_local_subsidiary" }, + { "id": "n_vehicle", "kind": "TASK", "task_id": "t_get_vehicle" }, + { "id": "n_arrangements", "kind": "TASK", "task_id": "t_make_arrangements" } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { "fn": "SUM" } + } + } + }, + "objective": { + "type": "MONO", + "targets": ["cost"], + "weights": { + "cost": 1.0 + } + } +} diff --git a/examples/literature/pautasso.json b/examples/literature/pautasso.json new file mode 100644 index 0000000..bef4687 --- /dev/null +++ b/examples/literature/pautasso.json @@ -0,0 +1,274 @@ +{ + "metadata": { + "id": "pautasso2009-restful-ecommerce", + "name": "RESTful e-Commerce scenario (Pautasso 2009)", + "version": "1.0.0", + "created_at": "2026-02-02T12:00:00Z", + "description": "QoS-aware composition instance derived from the running e-Commerce example in Pautasso (2009) 'BPEL for REST'. QoS numbers are illustrative (the paper specifies the workflow/API but not QoS measurements).", + "paper": { + "title": "RESTful Web service composition with BPEL for REST", + "authors": "C. Pautasso", + "year": 2009, + "doi": "10.1016/j.datak.2009.02.016" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 5000 } + }, + { + "id": "cost_usd", + "name": "Invocation cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 1000 } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 1 } + } + ], + "providers": [ + { + "id": "p_shop_a", + "name": "Shop Service A" + }, + { + "id": "p_shop_b", + "name": "Shop Service B" + }, + { + "id": "p_catalog_a", + "name": "Catalog Service A" + }, + { + "id": "p_catalog_b", + "name": "Catalog Service B" + }, + { + "id": "p_payment_a", + "name": "Payment Service A" + }, + { + "id": "p_payment_b", + "name": "Payment Service B" + } + ], + "tasks": [ + { "id": "t_create_order", "name": "Create order (POST /order)" }, + { "id": "t_request_quote", "name": "Request quote (POST /product/quote)" }, + { "id": "t_get_quote", "name": "Retrieve quote details (GET /quote)" }, + { "id": "t_add_item", "name": "Add line item (POST /order/item)" }, + { "id": "t_remove_item", "name": "Remove line item (DELETE /order/item)" }, + { "id": "t_get_amount", "name": "Get order amount (GET /order/amount)" }, + { "id": "t_checkout", "name": "Checkout (POST /order/payment)" }, + { "id": "t_charge_payment", "name": "Charge payment (POST /payment)" }, + { "id": "t_list_confirmed", "name": "List confirmed orders (GET /order/confirmed)" }, + { "id": "t_ship_order", "name": "Ship order (fulfillment action within Shop binding)" }, + { "id": "t_update_shipment", "name": "Update shipment info (PUT /order/shipment)" }, + { "id": "t_cancel_order", "name": "Cancel order (DELETE /order)" }, + { "id": "t_refund_payment", "name": "Refund payment (DELETE /payment)" } + ], + "candidates": [ + { "id": "c_shopA_create_order", "task_id": "t_create_order", "provider_id": "p_shop_a", "name": "ShopA POST /order", "features": { "latency_ms": 105, "cost_usd": 0.0006, "availability": 0.997 } }, + { "id": "c_shopB_create_order", "task_id": "t_create_order", "provider_id": "p_shop_b", "name": "ShopB POST /order", "features": { "latency_ms": 130, "cost_usd": 0.0004, "availability": 0.999 } }, + + { "id": "c_shopA_add_item", "task_id": "t_add_item", "provider_id": "p_shop_a", "name": "ShopA POST /order/item", "features": { "latency_ms": 135, "cost_usd": 0.0008, "availability": 0.997 } }, + { "id": "c_shopB_add_item", "task_id": "t_add_item", "provider_id": "p_shop_b", "name": "ShopB POST /order/item", "features": { "latency_ms": 160, "cost_usd": 0.0006, "availability": 0.999 } }, + + { "id": "c_shopA_remove_item", "task_id": "t_remove_item", "provider_id": "p_shop_a", "name": "ShopA DELETE /order/item", "features": { "latency_ms": 85, "cost_usd": 0.0005, "availability": 0.997 } }, + { "id": "c_shopB_remove_item", "task_id": "t_remove_item", "provider_id": "p_shop_b", "name": "ShopB DELETE /order/item", "features": { "latency_ms": 100, "cost_usd": 0.0003, "availability": 0.999 } }, + + { "id": "c_shopA_get_amount", "task_id": "t_get_amount", "provider_id": "p_shop_a", "name": "ShopA GET /order/amount", "features": { "latency_ms": 55, "cost_usd": 0.00025, "availability": 0.998 } }, + { "id": "c_shopB_get_amount", "task_id": "t_get_amount", "provider_id": "p_shop_b", "name": "ShopB GET /order/amount", "features": { "latency_ms": 75, "cost_usd": 0.00018, "availability": 0.999 } }, + + { "id": "c_shopA_checkout", "task_id": "t_checkout", "provider_id": "p_shop_a", "name": "ShopA POST /order/payment", "features": { "latency_ms": 150, "cost_usd": 0.0012, "availability": 0.996 } }, + { "id": "c_shopB_checkout", "task_id": "t_checkout", "provider_id": "p_shop_b", "name": "ShopB POST /order/payment", "features": { "latency_ms": 185, "cost_usd": 0.0010, "availability": 0.999 } }, + + { "id": "c_shopA_list_confirmed", "task_id": "t_list_confirmed", "provider_id": "p_shop_a", "name": "ShopA GET /order/confirmed", "features": { "latency_ms": 70, "cost_usd": 0.00025, "availability": 0.998 } }, + { "id": "c_shopB_list_confirmed", "task_id": "t_list_confirmed", "provider_id": "p_shop_b", "name": "ShopB GET /order/confirmed", "features": { "latency_ms": 90, "cost_usd": 0.00020, "availability": 0.999 } }, + + { "id": "c_shopA_ship_order", "task_id": "t_ship_order", "provider_id": "p_shop_a", "name": "ShopA fulfillment", "features": { "latency_ms": 480, "cost_usd": 0.05, "availability": 0.995 } }, + { "id": "c_shopB_ship_order", "task_id": "t_ship_order", "provider_id": "p_shop_b", "name": "ShopB fulfillment", "features": { "latency_ms": 520, "cost_usd": 0.045, "availability": 0.998 } }, + { "id": "c_shopA_update_shipment", "task_id": "t_update_shipment", "provider_id": "p_shop_a", "name": "ShopA PUT /order/shipment", "features": { "latency_ms": 95, "cost_usd": 0.0006, "availability": 0.997 } }, + { "id": "c_shopB_update_shipment", "task_id": "t_update_shipment", "provider_id": "p_shop_b", "name": "ShopB PUT /order/shipment", "features": { "latency_ms": 110, "cost_usd": 0.00045, "availability": 0.999 } }, + + { "id": "c_shopA_cancel_order", "task_id": "t_cancel_order", "provider_id": "p_shop_a", "name": "ShopA DELETE /order", "features": { "latency_ms": 85, "cost_usd": 0.00035, "availability": 0.998 } }, + { "id": "c_shopB_cancel_order", "task_id": "t_cancel_order", "provider_id": "p_shop_b", "name": "ShopB DELETE /order", "features": { "latency_ms": 95, "cost_usd": 0.00025, "availability": 0.999 } }, + + { "id": "c_catalogA_request_quote", "task_id": "t_request_quote", "provider_id": "p_catalog_a", "name": "CatalogA POST /product/quote", "features": { "latency_ms": 120, "cost_usd": 0.0020, "availability": 0.995 } }, + { "id": "c_catalogB_request_quote", "task_id": "t_request_quote", "provider_id": "p_catalog_b", "name": "CatalogB POST /product/quote", "features": { "latency_ms": 210, "cost_usd": 0.0015, "availability": 0.999 } }, + + { "id": "c_catalogA_get_quote", "task_id": "t_get_quote", "provider_id": "p_catalog_a", "name": "CatalogA GET /quote", "features": { "latency_ms": 85, "cost_usd": 0.0010, "availability": 0.995 } }, + { "id": "c_catalogB_get_quote", "task_id": "t_get_quote", "provider_id": "p_catalog_b", "name": "CatalogB GET /quote", "features": { "latency_ms": 155, "cost_usd": 0.0007, "availability": 0.999 } }, + + { "id": "c_paymentA_charge", "task_id": "t_charge_payment", "provider_id": "p_payment_a", "name": "PaymentA POST /payment", "features": { "latency_ms": 320, "cost_usd": 0.020, "availability": 0.997 } }, + { "id": "c_paymentB_charge", "task_id": "t_charge_payment", "provider_id": "p_payment_b", "name": "PaymentB POST /payment", "features": { "latency_ms": 380, "cost_usd": 0.017, "availability": 0.999 } }, + + { "id": "c_paymentA_refund", "task_id": "t_refund_payment", "provider_id": "p_payment_a", "name": "PaymentA DELETE /payment", "features": { "latency_ms": 240, "cost_usd": 0.015, "availability": 0.997 } }, + { "id": "c_paymentB_refund", "task_id": "t_refund_payment", "provider_id": "p_payment_b", "name": "PaymentB DELETE /payment", "features": { "latency_ms": 290, "cost_usd": 0.013, "availability": 0.999 } } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { "id": "n_create_order", "kind": "TASK", "task_id": "t_create_order" }, + { + "id": "n_edit_loop", + "kind": "LOOP", + "body": { + "id": "n_edit_action", + "kind": "XOR", + "branches": [ + { + "p": 0.7, + "child": { + "id": "n_add_item_seq", + "kind": "SEQ", + "children": [ + { "id": "n_request_quote", "kind": "TASK", "task_id": "t_request_quote" }, + { "id": "n_get_quote", "kind": "TASK", "task_id": "t_get_quote" }, + { "id": "n_add_item", "kind": "TASK", "task_id": "t_add_item" } + ] + } + }, + { "p": 0.1, "child": { "id": "n_remove_item", "kind": "TASK", "task_id": "t_remove_item" } }, + { "p": 0.2, "child": { "id": "n_get_amount", "kind": "TASK", "task_id": "t_get_amount" } } + ] + }, + "expected_iterations": 3 + }, + { + "id": "n_decide_checkout_or_cancel", + "kind": "XOR", + "branches": [ + { + "p": 0.9, + "child": { + "id": "n_checkout_seq", + "kind": "SEQ", + "children": [ + { "id": "n_checkout", "kind": "TASK", "task_id": "t_checkout" }, + { "id": "n_charge_payment", "kind": "TASK", "task_id": "t_charge_payment" }, + { + "id": "n_after_confirm", + "kind": "XOR", + "branches": [ + { + "p": 0.95, + "child": { + "id": "n_ship_seq", + "kind": "SEQ", + "children": [ + { "id": "n_list_confirmed", "kind": "TASK", "task_id": "t_list_confirmed" }, + { "id": "n_ship_order", "kind": "TASK", "task_id": "t_ship_order" }, + { "id": "n_update_shipment", "kind": "TASK", "task_id": "t_update_shipment" } + ] + } + }, + { + "p": 0.05, + "child": { + "id": "n_cancel_confirmed_seq", + "kind": "SEQ", + "children": [ + { "id": "n_cancel_confirmed", "kind": "TASK", "task_id": "t_cancel_order" }, + { "id": "n_refund_payment", "kind": "TASK", "task_id": "t_refund_payment" } + ] + } + } + ] + } + ] + } + }, + { "p": 0.1, "child": { "id": "n_cancel_before_confirm", "kind": "TASK", "task_id": "t_cancel_order" } } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { "fn": "SUM" }, + "and": { "fn": "MAX" }, + "loop": { "fn": "SCALED_SUM" } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { "fn": "SUM" }, + "and": { "fn": "SUM" }, + "loop": { "fn": "SCALED_SUM" } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { "fn": "PRODUCT" }, + "and": { "fn": "PRODUCT" }, + "loop": { "fn": "SCALED_PRODUCT" } + } + } + }, + "constraints": [ + { + "id": "bind_shop_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_create_order", + "t_add_item", + "t_remove_item", + "t_get_amount", + "t_checkout", + "t_list_confirmed", + "t_ship_order", + "t_update_shipment", + "t_cancel_order" + ] + }, + { + "id": "bind_catalog_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_request_quote", + "t_get_quote" + ] + }, + { + "id": "bind_payment_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_charge_payment", + "t_refund_payment" + ] + } + ], + "objective": { + "type": "MONO", + "targets": ["latency_ms", "cost_usd", "availability"], + "weights": { + "latency_ms": 0.5, + "cost_usd": 0.2, + "availability": 0.3 + } + } +} diff --git a/examples/literature/zhang.json b/examples/literature/zhang.json new file mode 100644 index 0000000..c88b4a6 --- /dev/null +++ b/examples/literature/zhang.json @@ -0,0 +1,185 @@ +{ + "metadata": { + "id": "zhang2014-entertainment-planner-running-example", + "name": "Personal Entertainment Planner (Zhang et al. 2014)", + "version": "1.0.0", + "created_at": "2026-02-02T12:00:00Z", + "description": "Modeled from the motivating example in 'Context-aware Generic Service Discovery and Service Composition' (IEEE MobServ 2014).", + "paper": { + "title": "Context-aware Generic Service Discovery and Service Composition", + "authors": "Y. Zhang et al.", + "year": 2014, + "doi": "10.1109/MobServ.2014.27" + } + }, + "features": [ + { + "id": "cost", + "name": "Total money cost (USD)", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 1000 } + }, + { + "id": "time", + "name": "Total time cost (minutes)", + "direction": "MINIMIZE", + "unit": "min", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 1440 } + }, + { + "id": "distance", + "name": "Distance from user's current location (meters)", + "direction": "MINIMIZE", + "unit": "m", + "scale": "RATIO", + "valid_range": { "min": 0, "max": 50000 } + } + ], + "providers": [ + { + "id": "p_rest_autre_saison", + "name": "Restaurant L’Autre Saison" + }, + { + "id": "p_cinema_banque_scotia", + "name": "Cinema Banque Scotia Montreal" + }, + { + "id": "p_seven_night_club", + "name": "Seven Night Club" + }, + { + "id": "p_local_shopping", + "name": "Local Shopping (nearby venue)" + } + ], + "tasks": [ + { "id": "t_dining", "name": "Restaurant / Dining activity" }, + { "id": "t_shopping", "name": "Shopping activity" }, + { "id": "t_movie", "name": "Movie activity" } + ], + "candidates": [ + { + "id": "c_dining_autre_saison", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison", + "features": { + "cost": 20, + "time": 60, + "distance": 1600 + } + }, + { + "id": "c_dining_seven_night_club", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Seven Night Club", + "features": { + "cost": 20, + "time": 60, + "distance": 1800 + } + }, + { + "id": "c_shopping_local", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue", + "features": { + "cost": 20, + "time": 45, + "distance": 1200 + } + }, + { + "id": "c_movie_the_help_banque_scotia", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal", + "features": { + "cost": 10, + "time": 135, + "distance": 1700 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { "id": "n_dining", "kind": "TASK", "task_id": "t_dining" }, + { "id": "n_shopping", "kind": "TASK", "task_id": "t_shopping" }, + { "id": "n_movie", "kind": "TASK", "task_id": "t_movie" } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { "fn": "SUM" }, + "and": { "fn": "SUM" }, + "loop": { "fn": "SCALED_SUM" } + } + }, + "time": { + "neutral": 0, + "compose": { + "seq": { "fn": "SUM" }, + "and": { "fn": "MAX" }, + "loop": { "fn": "SCALED_SUM" } + } + }, + "distance": { + "neutral": 0, + "compose": { + "seq": { "fn": "MAX" }, + "and": { "fn": "MAX" }, + "loop": { "fn": "SCALED_SUM" } + } + } + }, + "constraints": [ + { + "id": "c_within_2km", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "distance", + "op": "<=", + "value": 2000 + }, + { + "id": "c_time_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "time", + "op": "<=", + "value": 240, + "hard": false + }, + { + "id": "c_cost_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 100, + "hard": false + } + ], + "objective": { + "type": "MONO", + "targets": ["cost", "time", "distance"], + "weights": { + "cost": 0.25, + "time": 0.25, + "distance": 0.5 + } + } +} diff --git a/examples/minizinc-constrained-loop.json b/examples/minizinc-constrained-loop.json deleted file mode 100644 index 100e2db..0000000 --- a/examples/minizinc-constrained-loop.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "tasks": [ - { - "id": "T1", - "name": "T1" - } - ], - "candidates": [ - { - "id": "C1", - "task_id": "T1", - "provider_id": "P1", - "features": { - "latency": 10 - }, - "name": "C1" - }, - { - "id": "C2", - "task_id": "T1", - "provider_id": "P2", - "features": { - "latency": 20 - }, - "name": "C2" - } - ], - "composition": { - "type": "structured", - "root": { - "kind": "LOOP", - "expected_iterations": 5, - "body": { - "kind": "TASK", - "task_id": "T1", - "id": "dd947628" - }, - "id": "26ac2fe7" - } - }, - "features": [ - { - "id": "latency", - "name": "latency", - "unit": "unit", - "scale": "ratio", - "valid_range": { - "min": 0, - "max": 10000 - }, - "direction": "minimize" - } - ], - "aggregation_policies": { - "latency": { - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "sum" - }, - "xor": { - "fn": "sum" - }, - "loop": { - "fn": "sum" - } - }, - "neutral": 0, - "normalize": { - "type": "minmax", - "bounds": { - "min": 0, - "max": 10000 - } - } - } - }, - "objective": { - "type": "weighted_sum", - "weights": { - "latency": 1.0 - }, - "normalized": true - }, - "constraints": [ - { - "kind": "attribute_bound", - "attribute_id": "latency", - "op": "<", - "value": 1200000000.0, - "scope": "global", - "id": "c0" - } - ], - "metadata": { - "id": "6a985cfe-53e7-4dc1-8c23-bb045f100081", - "name": "Instance 10: Constrained Loop", - "version": "1.0", - "created_at": "2026-01-26T12:00:00Z", - "description": "Instance 10: Constrained Loop" - }, - "providers": [ - { - "id": "P2", - "name": "Provider P2" - }, - { - "id": "P1", - "name": "Provider P1" - } - ] -} \ No newline at end of file diff --git a/examples/minizinc-huge.json b/examples/minizinc-huge.json deleted file mode 100644 index 3b8ecef..0000000 --- a/examples/minizinc-huge.json +++ /dev/null @@ -1,578 +0,0 @@ -{ - "metadata": { - "id": "huge-minizinc", - "name": "Huge minizinc", - "version": "1.0", - "created_at": "2026-01-01T00:00:00Z" - }, - "tasks": [ - { - "id": "T1", - "name": "Task 1" - }, - { - "id": "T2", - "name": "Task 2" - }, - { - "id": "T3", - "name": "Task 3" - }, - { - "id": "T4", - "name": "Task 4" - }, - { - "id": "T5", - "name": "Task 5" - }, - { - "id": "T6", - "name": "Task 6" - }, - { - "id": "T7", - "name": "Task 7" - } - ], - "providers": [ - { - "id": "P1", - "name": "Provider 1" - }, - { - "id": "P2", - "name": "Provider 2" - }, - { - "id": "P3", - "name": "Provider 3" - } - ], - "candidates": [ - { - "id": "C1", - "task_id": "T1", - "provider_id": "P1", - "features": { - "cost": 10, - "latency": 5, - "reliability": 0.9, - "availability": 0.99, - "energy": 2 - } - }, - { - "id": "C2", - "task_id": "T1", - "provider_id": "P2", - "features": { - "cost": 20, - "latency": 10, - "reliability": 0.9, - "availability": 0.99, - "energy": 4 - } - }, - { - "id": "C3", - "task_id": "T1", - "provider_id": "P3", - "features": { - "cost": 30, - "latency": 15, - "reliability": 0.9, - "availability": 0.99, - "energy": 6 - } - }, - { - "id": "C4", - "task_id": "T2", - "provider_id": "P1", - "features": { - "cost": 40, - "latency": 20, - "reliability": 0.9, - "availability": 0.99, - "energy": 8 - } - }, - { - "id": "C5", - "task_id": "T2", - "provider_id": "P2", - "features": { - "cost": 50, - "latency": 25, - "reliability": 0.9, - "availability": 0.99, - "energy": 10 - } - }, - { - "id": "C6", - "task_id": "T2", - "provider_id": "P3", - "features": { - "cost": 60, - "latency": 30, - "reliability": 0.9, - "availability": 0.99, - "energy": 12 - } - }, - { - "id": "C7", - "task_id": "T3", - "provider_id": "P1", - "features": { - "cost": 70, - "latency": 35, - "reliability": 0.9, - "availability": 0.99, - "energy": 14 - } - }, - { - "id": "C8", - "task_id": "T3", - "provider_id": "P2", - "features": { - "cost": 80, - "latency": 40, - "reliability": 0.9, - "availability": 0.99, - "energy": 16 - } - }, - { - "id": "C9", - "task_id": "T3", - "provider_id": "P3", - "features": { - "cost": 90, - "latency": 45, - "reliability": 0.9, - "availability": 0.99, - "energy": 18 - } - }, - { - "id": "C10", - "task_id": "T4", - "provider_id": "P1", - "features": { - "cost": 100, - "latency": 50, - "reliability": 0.9, - "availability": 0.99, - "energy": 20 - } - }, - { - "id": "C11", - "task_id": "T4", - "provider_id": "P2", - "features": { - "cost": 110, - "latency": 55, - "reliability": 0.9, - "availability": 0.99, - "energy": 22 - } - }, - { - "id": "C12", - "task_id": "T4", - "provider_id": "P3", - "features": { - "cost": 120, - "latency": 60, - "reliability": 0.9, - "availability": 0.99, - "energy": 24 - } - }, - { - "id": "C13", - "task_id": "T5", - "provider_id": "P1", - "features": { - "cost": 130, - "latency": 65, - "reliability": 0.9, - "availability": 0.99, - "energy": 26 - } - }, - { - "id": "C14", - "task_id": "T5", - "provider_id": "P2", - "features": { - "cost": 140, - "latency": 70, - "reliability": 0.9, - "availability": 0.99, - "energy": 28 - } - }, - { - "id": "C15", - "task_id": "T5", - "provider_id": "P3", - "features": { - "cost": 150, - "latency": 75, - "reliability": 0.9, - "availability": 0.99, - "energy": 30 - } - }, - { - "id": "C16", - "task_id": "T6", - "provider_id": "P1", - "features": { - "cost": 160, - "latency": 80, - "reliability": 0.9, - "availability": 0.99, - "energy": 32 - } - }, - { - "id": "C17", - "task_id": "T6", - "provider_id": "P2", - "features": { - "cost": 170, - "latency": 85, - "reliability": 0.9, - "availability": 0.99, - "energy": 34 - } - }, - { - "id": "C18", - "task_id": "T6", - "provider_id": "P3", - "features": { - "cost": 180, - "latency": 90, - "reliability": 0.9, - "availability": 0.99, - "energy": 36 - } - }, - { - "id": "C19", - "task_id": "T7", - "provider_id": "P1", - "features": { - "cost": 190, - "latency": 95, - "reliability": 0.9, - "availability": 0.99, - "energy": 38 - } - }, - { - "id": "C20", - "task_id": "T7", - "provider_id": "P2", - "features": { - "cost": 200, - "latency": 100, - "reliability": 0.9, - "availability": 0.99, - "energy": 40 - } - }, - { - "id": "C21", - "task_id": "T7", - "provider_id": "P3", - "features": { - "cost": 210, - "latency": 105, - "reliability": 0.9, - "availability": 0.99, - "energy": 42 - } - } - ], - "features": [ - { - "id": "cost", - "name": "Cost", - "direction": "minimize", - "scale": "ratio", - "unit": "USD", - "valid_range": { - "min": 0, - "max": 100000 - } - }, - { - "id": "latency", - "name": "Latency", - "direction": "minimize", - "scale": "ratio", - "unit": "ms", - "valid_range": { - "min": 0, - "max": 10000 - } - }, - { - "id": "reliability", - "name": "Reliability", - "direction": "maximize", - "scale": "ratio", - "unit": "%", - "valid_range": { - "min": 0, - "max": 1 - } - }, - { - "id": "availability", - "name": "Availability", - "direction": "maximize", - "scale": "ratio", - "unit": "%", - "valid_range": { - "min": 0, - "max": 1 - } - }, - { - "id": "energy", - "name": "Energy", - "direction": "minimize", - "scale": "ratio", - "unit": "J", - "valid_range": { - "min": 0, - "max": 10000 - } - } - ], - "composition": { - "type": "structured", - "root": { - "id": "root_seq", - "kind": "SEQ", - "children": [ - { - "id": "n1", - "kind": "TASK", - "task_id": "T1" - }, - { - "id": "n2_and", - "kind": "AND", - "children": [ - { - "id": "n2a", - "kind": "TASK", - "task_id": "T2" - }, - { - "id": "n2b", - "kind": "TASK", - "task_id": "T3" - } - ] - }, - { - "id": "n3_xor", - "kind": "XOR", - "branches": [ - { - "p": 0.5, - "child": { - "id": "n3a", - "kind": "TASK", - "task_id": "T4" - } - }, - { - "p": 0.5, - "child": { - "id": "n3b", - "kind": "TASK", - "task_id": "T5" - } - } - ] - }, - { - "id": "n4_loop", - "kind": "LOOP", - "expected_iterations": 3, - "body": { - "id": "n4_inner_seq", - "kind": "SEQ", - "children": [ - { - "id": "n4a", - "kind": "TASK", - "task_id": "T6" - }, - { - "id": "n4b", - "kind": "TASK", - "task_id": "T7" - } - ] - } - } - ] - } - }, - "aggregation_policies": { - "cost": { - "neutral": 0, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - }, - "latency": { - "neutral": 0, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - }, - "reliability": { - "neutral": 1, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - }, - "availability": { - "neutral": 1, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - }, - "energy": { - "neutral": 0, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - } - }, - "objective": { - "type": "weighted_sum", - "weights": { - "cost": 1 - }, - "normalized": true - }, - "constraints": [ - { - "id": "c0", - "kind": "attribute_bound", - "scope": "global", - "attribute_id": "cost", - "op": "<=", - "value": 10000 - }, - { - "id": "c1", - "kind": "attribute_bound", - "scope": "local", - "task_id": "T1", - "attribute_id": "latency", - "op": "<=", - "value": 100 - }, - { - "id": "c2", - "kind": "dependency", - "type": "same_provider", - "tasks": [ - "T2", - "T3" - ] - } - ] -} \ No newline at end of file diff --git a/examples/minizinc-tight.json b/examples/minizinc-tight.json deleted file mode 100644 index fd1957f..0000000 --- a/examples/minizinc-tight.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "tasks": [ - { - "id": "T1", - "name": "T1" - }, - { - "id": "T2", - "name": "T2" - } - ], - "candidates": [ - { - "id": "C1", - "task_id": "T1", - "provider_id": "P1", - "features": { - "cost": 50 - }, - "name": "C1" - }, - { - "id": "C2", - "task_id": "T2", - "provider_id": "P1", - "features": { - "cost": 50 - }, - "name": "C2" - } - ], - "composition": { - "type": "structured", - "root": { - "kind": "SEQ", - "children": [ - { - "kind": "TASK", - "task_id": "T1", - "id": "086e5425" - }, - { - "kind": "TASK", - "task_id": "T2", - "id": "2b1d3b1c" - } - ], - "id": "41e13951" - } - }, - "features": [ - { - "id": "cost", - "name": "cost", - "unit": "unit", - "scale": "ratio", - "valid_range": { - "min": 0, - "max": 10000 - }, - "direction": "minimize" - } - ], - "aggregation_policies": { - "cost": { - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "sum" - }, - "xor": { - "fn": "sum" - }, - "loop": { - "fn": "sum" - } - }, - "neutral": 0, - "normalize": { - "type": "minmax", - "bounds": { - "min": 0, - "max": 10000 - } - } - } - }, - "objective": { - "type": "weighted_sum", - "weights": { - "cost": 1.0 - }, - "normalized": true - }, - "constraints": [], - "metadata": { - "id": "9abb4800-0925-47bf-8b39-7fe20cbff8aa", - "name": "Instance 9: Tight Constraints", - "version": "1.0", - "created_at": "2026-01-26T12:00:00Z", - "description": "Instance 9: Tight Constraints" - }, - "providers": [ - { - "id": "P1", - "name": "Provider P1" - } - ] -} \ No newline at end of file diff --git a/examples/random-search-example.json b/examples/random-search-example.json deleted file mode 100644 index 6a413da..0000000 --- a/examples/random-search-example.json +++ /dev/null @@ -1,216 +0,0 @@ -{ - "metadata": { - "id": "many-obj-complex-example", - "name": "Many-OBJ Complex Workflow", - "version": "1.0", - "created_at": "2024-01-20T12:00:00Z" - }, - "features": [ - { - "id": "cost", - "name": "Cost", - "direction": "minimize", - "unit": "USD", - "scale": "ratio", - "valid_range": { - "min": 0, - "max": 1000 - } - }, - { - "id": "time", - "name": "Response Time", - "direction": "minimize", - "unit": "ms", - "scale": "ratio", - "valid_range": { - "min": 0, - "max": 5000 - } - } - ], - "tasks": [ - { - "id": "payment", - "name": "Payment Processing" - }, - { - "id": "inventory", - "name": "Inventory Check" - }, - { - "id": "shipping", - "name": "Shipping Logistics" - } - ], - "providers": [ - { - "id": "stripe", - "name": "Stripe" - }, - { - "id": "paypal", - "name": "PayPal" - }, - { - "id": "aws", - "name": "AWS Warehouse" - }, - { - "id": "azure", - "name": "Azure Inventory" - }, - { - "id": "fedex", - "name": "FedEx" - }, - { - "id": "ups", - "name": "UPS" - } - ], - "candidates": [ - { - "id": "pay_stripe", - "task_id": "payment", - "provider_id": "stripe", - "features": { - "cost": 0.3, - "time": 200 - } - }, - { - "id": "pay_paypal", - "task_id": "payment", - "provider_id": "paypal", - "features": { - "cost": 0.5, - "time": 150 - } - }, - { - "id": "inv_aws", - "task_id": "inventory", - "provider_id": "aws", - "features": { - "cost": 0.1, - "time": 50 - } - }, - { - "id": "inv_azure", - "task_id": "inventory", - "provider_id": "azure", - "features": { - "cost": 0.05, - "time": 80 - } - }, - { - "id": "ship_fedex", - "task_id": "shipping", - "provider_id": "fedex", - "features": { - "cost": 5.0, - "time": 1000 - } - }, - { - "id": "ship_ups", - "task_id": "shipping", - "provider_id": "ups", - "features": { - "cost": 4.5, - "time": 1200 - } - } - ], - "composition": { - "type": "structured", - "root": { - "id": "root_seq", - "kind": "SEQ", - "children": [ - { - "id": "task_payment", - "kind": "TASK", - "task_id": "payment" - }, - { - "id": "par_flow", - "kind": "AND", - "children": [ - { - "id": "task_inv", - "kind": "TASK", - "task_id": "inventory" - }, - { - "id": "task_ship", - "kind": "TASK", - "task_id": "shipping" - } - ] - } - ] - } - }, - "aggregation_policies": { - "cost": { - "neutral": 0, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "sum" - }, - "xor": { - "fn": "sum" - }, - "loop": { - "fn": "sum" - } - }, - "normalize": { - "type": "minmax", - "bounds": { - "min": 0, - "max": 1000 - } - } - }, - "time": { - "neutral": 0, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "sum" - }, - "loop": { - "fn": "sum" - } - }, - "normalize": { - "type": "minmax", - "bounds": { - "min": 0, - "max": 5000 - } - } - } - }, - "objective": { - "type": "weighted_sum", - "weights": { - "cost": 0.5, - "time": 0.5 - }, - "normalized": true - } -} \ No newline at end of file diff --git a/examples/random-search-huge.json b/examples/random-search-huge.json deleted file mode 100644 index 2be9fb9..0000000 --- a/examples/random-search-huge.json +++ /dev/null @@ -1,560 +0,0 @@ -{ - "metadata": { - "id": "huge-random", - "name": "Huge random", - "version": "1.0", - "created_at": "2026-01-01T00:00:00Z" - }, - "tasks": [ - { - "id": "T1", - "name": "Task 1" - }, - { - "id": "T2", - "name": "Task 2" - }, - { - "id": "T3", - "name": "Task 3" - }, - { - "id": "T4", - "name": "Task 4" - }, - { - "id": "T5", - "name": "Task 5" - }, - { - "id": "T6", - "name": "Task 6" - }, - { - "id": "T7", - "name": "Task 7" - } - ], - "providers": [ - { - "id": "P1", - "name": "Provider 1" - }, - { - "id": "P2", - "name": "Provider 2" - }, - { - "id": "P3", - "name": "Provider 3" - } - ], - "candidates": [ - { - "id": "C1", - "task_id": "T1", - "provider_id": "P1", - "features": { - "cost": 10, - "latency": 5, - "reliability": 0.9, - "availability": 0.99, - "energy": 2 - } - }, - { - "id": "C2", - "task_id": "T1", - "provider_id": "P2", - "features": { - "cost": 20, - "latency": 10, - "reliability": 0.9, - "availability": 0.99, - "energy": 4 - } - }, - { - "id": "C3", - "task_id": "T1", - "provider_id": "P3", - "features": { - "cost": 30, - "latency": 15, - "reliability": 0.9, - "availability": 0.99, - "energy": 6 - } - }, - { - "id": "C4", - "task_id": "T2", - "provider_id": "P1", - "features": { - "cost": 40, - "latency": 20, - "reliability": 0.9, - "availability": 0.99, - "energy": 8 - } - }, - { - "id": "C5", - "task_id": "T2", - "provider_id": "P2", - "features": { - "cost": 50, - "latency": 25, - "reliability": 0.9, - "availability": 0.99, - "energy": 10 - } - }, - { - "id": "C6", - "task_id": "T2", - "provider_id": "P3", - "features": { - "cost": 60, - "latency": 30, - "reliability": 0.9, - "availability": 0.99, - "energy": 12 - } - }, - { - "id": "C7", - "task_id": "T3", - "provider_id": "P1", - "features": { - "cost": 70, - "latency": 35, - "reliability": 0.9, - "availability": 0.99, - "energy": 14 - } - }, - { - "id": "C8", - "task_id": "T3", - "provider_id": "P2", - "features": { - "cost": 80, - "latency": 40, - "reliability": 0.9, - "availability": 0.99, - "energy": 16 - } - }, - { - "id": "C9", - "task_id": "T3", - "provider_id": "P3", - "features": { - "cost": 90, - "latency": 45, - "reliability": 0.9, - "availability": 0.99, - "energy": 18 - } - }, - { - "id": "C10", - "task_id": "T4", - "provider_id": "P1", - "features": { - "cost": 100, - "latency": 50, - "reliability": 0.9, - "availability": 0.99, - "energy": 20 - } - }, - { - "id": "C11", - "task_id": "T4", - "provider_id": "P2", - "features": { - "cost": 110, - "latency": 55, - "reliability": 0.9, - "availability": 0.99, - "energy": 22 - } - }, - { - "id": "C12", - "task_id": "T4", - "provider_id": "P3", - "features": { - "cost": 120, - "latency": 60, - "reliability": 0.9, - "availability": 0.99, - "energy": 24 - } - }, - { - "id": "C13", - "task_id": "T5", - "provider_id": "P1", - "features": { - "cost": 130, - "latency": 65, - "reliability": 0.9, - "availability": 0.99, - "energy": 26 - } - }, - { - "id": "C14", - "task_id": "T5", - "provider_id": "P2", - "features": { - "cost": 140, - "latency": 70, - "reliability": 0.9, - "availability": 0.99, - "energy": 28 - } - }, - { - "id": "C15", - "task_id": "T5", - "provider_id": "P3", - "features": { - "cost": 150, - "latency": 75, - "reliability": 0.9, - "availability": 0.99, - "energy": 30 - } - }, - { - "id": "C16", - "task_id": "T6", - "provider_id": "P1", - "features": { - "cost": 160, - "latency": 80, - "reliability": 0.9, - "availability": 0.99, - "energy": 32 - } - }, - { - "id": "C17", - "task_id": "T6", - "provider_id": "P2", - "features": { - "cost": 170, - "latency": 85, - "reliability": 0.9, - "availability": 0.99, - "energy": 34 - } - }, - { - "id": "C18", - "task_id": "T6", - "provider_id": "P3", - "features": { - "cost": 180, - "latency": 90, - "reliability": 0.9, - "availability": 0.99, - "energy": 36 - } - }, - { - "id": "C19", - "task_id": "T7", - "provider_id": "P1", - "features": { - "cost": 190, - "latency": 95, - "reliability": 0.9, - "availability": 0.99, - "energy": 38 - } - }, - { - "id": "C20", - "task_id": "T7", - "provider_id": "P2", - "features": { - "cost": 200, - "latency": 100, - "reliability": 0.9, - "availability": 0.99, - "energy": 40 - } - }, - { - "id": "C21", - "task_id": "T7", - "provider_id": "P3", - "features": { - "cost": 210, - "latency": 105, - "reliability": 0.9, - "availability": 0.99, - "energy": 42 - } - } - ], - "features": [ - { - "id": "cost", - "name": "Cost", - "direction": "minimize", - "scale": "ratio", - "unit": "USD", - "valid_range": { - "min": 0, - "max": 100000 - } - }, - { - "id": "latency", - "name": "Latency", - "direction": "minimize", - "scale": "ratio", - "unit": "ms", - "valid_range": { - "min": 0, - "max": 10000 - } - }, - { - "id": "reliability", - "name": "Reliability", - "direction": "maximize", - "scale": "ratio", - "unit": "%", - "valid_range": { - "min": 0, - "max": 1 - } - }, - { - "id": "availability", - "name": "Availability", - "direction": "maximize", - "scale": "ratio", - "unit": "%", - "valid_range": { - "min": 0, - "max": 1 - } - }, - { - "id": "energy", - "name": "Energy", - "direction": "minimize", - "scale": "ratio", - "unit": "J", - "valid_range": { - "min": 0, - "max": 10000 - } - } - ], - "composition": { - "type": "structured", - "root": { - "id": "root_seq", - "kind": "SEQ", - "children": [ - { - "id": "n1", - "kind": "TASK", - "task_id": "T1" - }, - { - "id": "n2_and", - "kind": "AND", - "children": [ - { - "id": "n2a", - "kind": "TASK", - "task_id": "T2" - }, - { - "id": "n2b", - "kind": "TASK", - "task_id": "T3" - } - ] - }, - { - "id": "n3_xor", - "kind": "XOR", - "branches": [ - { - "p": 0.5, - "child": { - "id": "n3a", - "kind": "TASK", - "task_id": "T4" - } - }, - { - "p": 0.5, - "child": { - "id": "n3b", - "kind": "TASK", - "task_id": "T5" - } - } - ] - }, - { - "id": "n4_loop", - "kind": "LOOP", - "expected_iterations": 3, - "body": { - "id": "n4_inner_seq", - "kind": "SEQ", - "children": [ - { - "id": "n4a", - "kind": "TASK", - "task_id": "T6" - }, - { - "id": "n4b", - "kind": "TASK", - "task_id": "T7" - } - ] - } - } - ] - } - }, - "aggregation_policies": { - "cost": { - "neutral": 0, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - }, - "latency": { - "neutral": 0, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - }, - "reliability": { - "neutral": 1, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - }, - "availability": { - "neutral": 1, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - }, - "energy": { - "neutral": 0, - "normalize": { - "type": "identity" - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "weighted_sum", - "expr": "sum(w * x)" - }, - "loop": { - "fn": "sum" - } - } - } - }, - "objective": { - "type": "weighted_sum", - "weights": { - "cost": 1 - }, - "normalized": true - }, - "constraints": [ - { - "id": "c0", - "kind": "attribute_bound", - "scope": "global", - "attribute_id": "cost", - "op": "<=", - "value": 10000 - } - ] -} \ No newline at end of file diff --git a/examples/random-search-valid.json b/examples/random-search-valid.json deleted file mode 100644 index f3d6271..0000000 --- a/examples/random-search-valid.json +++ /dev/null @@ -1,167 +0,0 @@ -{ - "metadata": { - "id": "test-many-obj-01", - "name": "Many-OBJ Test Instance", - "version": "1.0", - "created_at": "2023-10-27T10:00:00Z" - }, - "providers": [ - { - "id": "p1", - "name": "Provider 1" - }, - { - "id": "p2", - "name": "Provider 2" - } - ], - "tasks": [ - { - "id": "t1", - "name": "Task A" - }, - { - "id": "t2", - "name": "Task B" - } - ], - "composition": { - "type": "structured", - "root": { - "id": "n1", - "kind": "SEQ", - "children": [ - { - "id": "t1", - "kind": "TASK", - "task_id": "t1" - }, - { - "id": "t2", - "kind": "TASK", - "task_id": "t2" - } - ] - } - }, - "candidates": [ - { - "id": "s1", - "task_id": "t1", - "provider_id": "p1", - "features": { - "cost": 10.0, - "time": 50.0 - } - }, - { - "id": "s2", - "task_id": "t1", - "provider_id": "p2", - "features": { - "cost": 12.0, - "time": 45.0 - } - }, - { - "id": "s3", - "task_id": "t2", - "provider_id": "p1", - "features": { - "cost": 5.0, - "time": 20.0 - } - }, - { - "id": "s4", - "task_id": "t2", - "provider_id": "p2", - "features": { - "cost": 8.0, - "time": 15.0 - } - } - ], - "features": [ - { - "id": "cost", - "name": "Cost", - "direction": "minimize", - "unit": "USD", - "scale": "ratio", - "valid_range": { - "min": 0, - "max": 1000 - } - }, - { - "id": "time", - "name": "Response Time", - "direction": "minimize", - "unit": "ms", - "scale": "ratio", - "valid_range": { - "min": 0, - "max": 5000 - } - } - ], - "objective": { - "type": "weighted_sum", - "weights": { - "cost": 0.5, - "time": 0.5 - }, - "normalized": true - }, - "aggregation_policies": { - "cost": { - "neutral": 0, - "normalize": { - "type": "minmax", - "bounds": { - "min": 0, - "max": 100 - } - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "sum" - }, - "loop": { - "fn": "sum" - } - } - }, - "time": { - "neutral": 0, - "normalize": { - "type": "minmax", - "bounds": { - "min": 0, - "max": 1000 - } - }, - "compose": { - "seq": { - "fn": "sum" - }, - "and": { - "fn": "max" - }, - "xor": { - "fn": "sum" - }, - "loop": { - "fn": "sum" - } - } - } - } -} \ No newline at end of file diff --git a/experimentation/generator.py b/experimentation/generator.py new file mode 100644 index 0000000..c3ea6a5 --- /dev/null +++ b/experimentation/generator.py @@ -0,0 +1,946 @@ +import copy +import itertools +import json +import math +import random +from datetime import datetime, timezone +from pathlib import Path +from typing import Any, Dict, Iterable, List, Sequence, Set, Tuple + +# Configuration (no CLI args; deterministic generation) +ROOT_DIR = Path(__file__).resolve().parents[1] +LITERATURE_DIR = ROOT_DIR / "examples" / "literature" +DEFAULT_OUTPUT_DIR = ROOT_DIR / "experimentation" / "instances" + +SCENARIOS = [ + "benatallah.json", + "bultan.json", + "cremaschi.json", + "netedu.json", + "pautasso.json", + "zhang.json", +] + +TARGET_BINDING_SPACE = 1_000_000 +EXTRA_FEATURES_PER_SCENARIO = 3 +EXTRA_PROVIDERS_PER_SCENARIO = 5 + +RANDOM_SEED = 12345 + +def load_scenario(filename: str) -> Dict[str, Any]: + with (LITERATURE_DIR / filename).open("r", encoding="utf-8") as f: + return json.load(f) + +def save_instance(instance: Dict[str, Any], output_dir: Path, name: str) -> Path: + output_dir.mkdir(parents=True, exist_ok=True) + filepath = output_dir / name + with filepath.open("w", encoding="utf-8") as f: + json.dump(instance, f, indent=2, ensure_ascii=False) + print(f"Generated: {filepath}") + return filepath + +def calculate_binding_space(instance: Dict[str, Any]) -> int: + tasks = [t["id"] for t in instance.get("tasks", [])] + if not tasks: + return 0 + + counts: Dict[str, int] = {tid: 0 for tid in tasks} + for candidate in instance.get("candidates", []): + tid = candidate.get("task_id") + if tid in counts: + counts[tid] += 1 + + if any(v <= 0 for v in counts.values()): + return 0 + + space = 1 + for v in counts.values(): + space *= v + return space + +def _id_set(items: Iterable[Dict[str, Any]]) -> Set[str]: + return {str(x.get("id")) for x in items if "id" in x} + + +def _unique_id(prefix: str, used: Set[str]) -> str: + i = 1 + while True: + candidate = f"{prefix}{i}" + if candidate not in used: + used.add(candidate) + return candidate + i += 1 + + +def _feature_map(instance: Dict[str, Any]) -> Dict[str, Dict[str, Any]]: + return {f["id"]: f for f in instance.get("features", [])} + + +def _clamp(v: float, mn: float, mx: float) -> float: + return max(mn, min(mx, v)) + + +def _range_for_feature(feature_def: Dict[str, Any]) -> Tuple[float, float]: + vr = feature_def.get("valid_range") or {} + return float(vr.get("min", 0.0)), float(vr.get("max", 1.0)) + + +def _ensure_aggregation_policy_for_feature( + instance: Dict[str, Any], feature_id: str, direction: str +) -> None: + policies = instance.setdefault("aggregation_policies", {}) + if feature_id in policies: + return + + # Prefer copying an existing policy of the same direction. + fmap = _feature_map(instance) + for existing_id, policy in policies.items(): + fdef = fmap.get(existing_id) + if fdef and fdef.get("direction") == direction: + policies[feature_id] = copy.deepcopy(policy) + return + + if direction == "MAXIMIZE": + policies[feature_id] = { + "neutral": 1, + "compose": { + "seq": {"fn": "PRODUCT"}, + "and": {"fn": "PRODUCT"}, + "loop": {"fn": "SCALED_PRODUCT"}, + }, + } + else: + policies[feature_id] = { + "neutral": 0, + "compose": { + "seq": {"fn": "SUM"}, + "and": {"fn": "MAX"}, + "loop": {"fn": "SCALED_SUM"}, + }, + } + + +def _composition_operators_used(instance: Dict[str, Any]) -> Set[str]: + operators: Set[str] = set() + root = (instance.get("composition") or {}).get("root") + if not isinstance(root, dict): + return operators + + def walk(node: Dict[str, Any]) -> None: + kind = str(node.get("kind", "")).upper() + if kind == "SEQ": + operators.add("seq") + for child in node.get("children", []) or []: + if isinstance(child, dict): + walk(child) + elif kind == "AND": + operators.add("and") + for child in node.get("children", []) or []: + if isinstance(child, dict): + walk(child) + elif kind == "XOR": + operators.add("xor") + for branch in node.get("branches", []) or []: + if isinstance(branch, dict) and isinstance(branch.get("child"), dict): + walk(branch["child"]) + elif kind == "LOOP": + operators.add("loop") + body = node.get("body") + if isinstance(body, dict): + walk(body) + + walk(root) + return operators + + +def _default_compose_fn(direction: str, operator: str) -> str: + if operator == "xor": + # Expected-value style default for probabilistic branch composition. + return "SCALED_SUM" + if direction == "MAXIMIZE": + return { + "seq": "PRODUCT", + "and": "PRODUCT", + "loop": "SCALED_PRODUCT", + }.get(operator, "PRODUCT") + return { + "seq": "SUM", + "and": "MAX", + "loop": "SCALED_SUM", + }.get(operator, "SUM") + + +def ensure_aggregation_policies_complete(instance: Dict[str, Any]) -> None: + fmap = _feature_map(instance) + policies = instance.setdefault("aggregation_policies", {}) + + # 1) Ensure every feature has a policy. + for feature_id, feature_def in fmap.items(): + _ensure_aggregation_policy_for_feature( + instance, + feature_id, + str(feature_def.get("direction", "MINIMIZE")), + ) + + # 2) Ensure each policy has functions for every operator used in composition. + required_ops = _composition_operators_used(instance) + if not required_ops: + return + + for feature_id, feature_def in fmap.items(): + direction = str(feature_def.get("direction", "MINIMIZE")) + policy = policies.setdefault(feature_id, {}) + compose = policy.setdefault("compose", {}) + + for op in sorted(required_ops): + if op in compose: + continue + compose[op] = {"fn": _default_compose_fn(direction, op)} + + +def expand_features(instance: Dict[str, Any], count: int) -> None: + used_feature_ids = _id_set(instance.get("features", [])) + existing_features = instance.get("features", []) + + # Alternate directions to have both MINIMIZE and MAXIMIZE features. + directions = ["MINIMIZE", "MAXIMIZE"] + for i in range(count): + direction = directions[i % len(directions)] + new_id = _unique_id("gen_feat_", used_feature_ids) + + if direction == "MAXIMIZE": + valid_range = {"min": 0, "max": 1} + unit = "ratio" + else: + valid_range = {"min": 0, "max": 1000} + unit = "unit" + + existing_features.append( + { + "id": new_id, + "name": f"Generated feature {new_id}", + "direction": direction, + "unit": unit, + "scale": "RATIO", + "valid_range": valid_range, + } + ) + _ensure_aggregation_policy_for_feature(instance, new_id, direction) + + # Ensure every candidate has a numeric value for every feature. + fmap = _feature_map(instance) + for candidate in instance.get("candidates", []): + feats = candidate.setdefault("features", {}) + for fid, fdef in fmap.items(): + if fid in feats and isinstance(feats[fid], (int, float)): + continue + mn, mx = _range_for_feature(fdef) + # Default to mid-range for determinism. + feats[fid] = round((mn + mx) / 2.0, 6) + + +def expand_providers(instance: Dict[str, Any], count: int) -> None: + providers = instance.setdefault("providers", []) + used_provider_ids = _id_set(providers) + + # Shared provider ensures SAME_PROVIDER dependency constraints are feasible. + if "p_gen_shared" not in used_provider_ids: + providers.append({"id": "p_gen_shared", "name": "Generated Shared Provider"}) + used_provider_ids.add("p_gen_shared") + + for _ in range(count): + pid = _unique_id("p_gen_", used_provider_ids) + providers.append({"id": pid, "name": f"Generated Provider {pid}"}) + + +def _candidate_template_for_task(instance: Dict[str, Any], task_id: str) -> Dict[str, Any]: + for c in instance.get("candidates", []): + if c.get("task_id") == task_id: + return c + # Fallback minimal candidate (should be rare; schema expects candidates) + providers = [p["id"] for p in instance.get("providers", [])] + provider_id = providers[0] if providers else "p_gen_shared" + return {"id": f"tmpl_{task_id}", "task_id": task_id, "provider_id": provider_id, "name": task_id, "features": {}} + + +def _generate_feature_values_from_base( + base_features: Dict[str, Any], fmap: Dict[str, Dict[str, Any]], rng: random.Random +) -> Dict[str, float]: + out: Dict[str, float] = {} + for fid, fdef in fmap.items(): + mn, mx = _range_for_feature(fdef) + base_val = base_features.get(fid) + if isinstance(base_val, (int, float)): + # Mild perturbation keeps values realistic and within bounds. + jitter = rng.uniform(0.97, 1.03) + v = float(base_val) * jitter + else: + # Deterministic-ish random around mid-range. + v = (mn + mx) / 2.0 + rng.uniform(-0.05, 0.05) * (mx - mn) + v = _clamp(v, mn, mx) + # Keep ratios with higher precision; costs/latencies to 2 decimals. + out[fid] = round(v, 6 if mx <= 1.0 else 2) + return out + + +def ensure_min_candidates_per_task( + instance: Dict[str, Any], min_per_task: int, rng: random.Random +) -> None: + tasks = [t["id"] for t in instance.get("tasks", [])] + if not tasks: + return + + candidates = instance.setdefault("candidates", []) + used_candidate_ids = _id_set(candidates) + fmap = _feature_map(instance) + provider_ids = [p["id"] for p in instance.get("providers", [])] + if not provider_ids: + expand_providers(instance, EXTRA_PROVIDERS_PER_SCENARIO) + provider_ids = [p["id"] for p in instance.get("providers", [])] + + # Ensure at least 1 shared-provider candidate per task. + shared_provider_id = "p_gen_shared" + for task_id in tasks: + has_shared = any( + c.get("task_id") == task_id and c.get("provider_id") == shared_provider_id + for c in candidates + ) + if not has_shared: + base = _candidate_template_for_task(instance, task_id) + cid = _unique_id(f"{task_id}_gen_", used_candidate_ids) + candidates.append( + { + "id": cid, + "task_id": task_id, + "provider_id": shared_provider_id, + "name": f"{base.get('name', task_id)} (Gen Shared)", + "features": _generate_feature_values_from_base(base.get("features", {}), fmap, rng), + } + ) + + # Grow each task up to min_per_task candidates, round-robin over providers. + providers_cycle = [pid for pid in provider_ids if pid != shared_provider_id] + if not providers_cycle: + providers_cycle = [shared_provider_id] + + for task_id in tasks: + existing = [c for c in candidates if c.get("task_id") == task_id] + if not existing: + existing = [_candidate_template_for_task(instance, task_id)] + base = existing[0] + + while len([c for c in candidates if c.get("task_id") == task_id]) < min_per_task: + provider_id = providers_cycle[len(used_candidate_ids) % len(providers_cycle)] + cid = _unique_id(f"{task_id}_gen_", used_candidate_ids) + candidates.append( + { + "id": cid, + "task_id": task_id, + "provider_id": provider_id, + "name": f"{base.get('name', task_id)} (Gen {provider_id})", + "features": _generate_feature_values_from_base(base.get("features", {}), fmap, rng), + } + ) + + +def ensure_binding_space_gt(instance: Dict[str, Any], target: int, rng: random.Random) -> None: + tasks = [t["id"] for t in instance.get("tasks", [])] + if not tasks: + return + + # Uniform lower bound per task keeps instances compact while guaranteeing product. + t = len(tasks) + min_per_task = int(math.ceil(target ** (1.0 / t))) + min_per_task = max(min_per_task, 2) + ensure_min_candidates_per_task(instance, min_per_task, rng) + + # If still short due to uneven distributions, top-up deterministically. + while calculate_binding_space(instance) < target: + counts: Dict[str, int] = {tid: 0 for tid in tasks} + for c in instance.get("candidates", []): + tid = c.get("task_id") + if tid in counts: + counts[tid] += 1 + tid_to_grow = min(counts.items(), key=lambda kv: (kv[1], kv[0]))[0] + ensure_min_candidates_per_task(instance, counts[tid_to_grow] + 1, rng) + +def _quantile(values: Sequence[float], q: float) -> float: + if not values: + return 0.0 + if q <= 0: + return float(min(values)) + if q >= 1: + return float(max(values)) + vs = sorted(float(v) for v in values) + idx = (len(vs) - 1) * q + lo = int(math.floor(idx)) + hi = int(math.ceil(idx)) + if lo == hi: + return vs[lo] + frac = idx - lo + return vs[lo] * (1 - frac) + vs[hi] * frac + + +def _candidates_by_task(instance: Dict[str, Any]) -> Dict[str, List[Dict[str, Any]]]: + by_task: Dict[str, List[Dict[str, Any]]] = {} + for c in instance.get("candidates", []) or []: + tid = c.get("task_id") + if not isinstance(tid, str): + continue + by_task.setdefault(tid, []).append(c) + for task_id in by_task: + by_task[task_id].sort(key=lambda cand: str(cand.get("id", ""))) + return by_task + + +def _candidate_lookup(instance: Dict[str, Any]) -> Dict[str, Dict[str, Any]]: + return {str(c.get("id")): c for c in (instance.get("candidates", []) or []) if "id" in c} + + +def _default_for(feature_id: str, features: Dict[str, Any], agg_policies: Dict[str, Any]) -> float: + policy = agg_policies.get(feature_id, {}) + if "neutral" in policy and isinstance(policy.get("neutral"), (int, float)): + return float(policy["neutral"]) + feat = features.get(feature_id, {}) + direction = feat.get("direction") + vr = feat.get("valid_range") or {} + if direction in ("maximize", "MAXIMIZE"): + return float(vr.get("min", 0.0)) + return float(vr.get("max", 0.0)) + + +def _agg_fn(fn: str, values: List[float], weights: List[float] = None) -> float: + if not values: + return 0.0 + fn_lower = (fn or "").lower() + if fn_lower in ("weighted_sum",): + ws = weights or [1.0] * len(values) + return sum(v * w for v, w in zip(values, ws)) + if fn_lower == "sum": + if weights is not None: + return sum(v * w for v, w in zip(values, weights)) + return sum(values) + if fn_lower == "product": + res = 1.0 + for v in values: + res *= v + return res + if fn_lower == "max": + return max(values) + if fn_lower == "min": + return min(values) + return sum(values) + + +def _compose_value( + node: Dict[str, Any], + feature_id: str, + selected_by_task: Dict[str, Dict[str, Any]], + features: Dict[str, Any], + agg_policies: Dict[str, Any], +) -> float: + kind = node.get("kind") + policy = agg_policies.get(feature_id, {}) + compose = policy.get("compose", {}) + + if kind == "TASK": + task_id = node.get("task_id") + cand = selected_by_task.get(task_id) + if cand is None: + return _default_for(feature_id, features, agg_policies) + return float((cand.get("features", {}) or {}).get(feature_id, _default_for(feature_id, features, agg_policies))) + + if kind in ("SEQ", "AND"): + children = node.get("children", []) or [] + values = [_compose_value(c, feature_id, selected_by_task, features, agg_policies) for c in children] + fn = compose.get("seq" if kind == "SEQ" else "and", {}).get("fn") + return _agg_fn(fn or ("sum" if kind == "SEQ" else "max"), values) + + if kind == "XOR": + branches = node.get("branches", []) or [] + values = [_compose_value((b or {}).get("child", {}), feature_id, selected_by_task, features, agg_policies) for b in branches] + probs = [float((b or {}).get("p", 0.0)) for b in branches] + fn = compose.get("xor", {}).get("fn") + if fn in (None, "sum", "weighted_sum", "scaled_sum", "SCALED_SUM"): + return _agg_fn("weighted_sum", values, probs) + return _agg_fn(fn, values) + + if kind == "LOOP": + body = node.get("body", {}) or {} + body_val = _compose_value(body, feature_id, selected_by_task, features, agg_policies) + fn = compose.get("loop", {}).get("fn") + iterations = node.get("expected_iterations") + if iterations is None: + bounds = node.get("bounds") or {} + iterations = bounds.get("max", 1) + c = float(iterations) + + fn_lower = (fn or "sum").lower() + if "product" in fn_lower: + return float(body_val ** c) + if "sum" in fn_lower or "wsum" in fn_lower or "scale" in fn_lower: + return float(body_val * c) + return body_val + + return _default_for(feature_id, features, agg_policies) + + +def _compute_aggregated_qos(instance: Dict[str, Any], binding: Dict[str, str]) -> Dict[str, float]: + root = (instance.get("composition", {}) or {}).get("root", {}) + features = {f["id"]: f for f in (instance.get("features", []) or [])} + agg_policies = instance.get("aggregation_policies", {}) or {} + by_id = _candidate_lookup(instance) + selected_by_task = { + task_id: by_id[cand_id] + for task_id, cand_id in binding.items() + if cand_id in by_id + } + out: Dict[str, float] = {} + for fid in features.keys(): + out[fid] = _compose_value(root, fid, selected_by_task, features, agg_policies) + return out + + +def _check_bound(current: float, op: str, rhs: float) -> bool: + if op == "<=": + return current <= rhs + if op == "<": + return current < rhs + if op == ">=": + return current >= rhs + if op == ">": + return current > rhs + if op == "==": + return abs(current - rhs) <= 1e-9 + if op == "!=": + return abs(current - rhs) > 1e-9 + return True + + +def _binding_satisfies_hard_constraints(instance: Dict[str, Any], binding: Dict[str, str]) -> bool: + by_id = _candidate_lookup(instance) + selected_by_task = { + task_id: by_id[cid] + for task_id, cid in binding.items() + if cid in by_id + } + aggregated_qos = _compute_aggregated_qos(instance, binding) + + for c in (instance.get("constraints", []) or []): + if c.get("hard", True) is False: + continue + kind = str(c.get("kind", "")).upper() + + if kind == "ATTRIBUTE_BOUND": + fid = c.get("attribute_id") + op = c.get("op") + val = c.get("value") + if not fid or not isinstance(val, (int, float)): + continue + rhs = float(val) + scope = str(c.get("scope", "GLOBAL")).upper() + + if scope == "LOCAL": + for task_id in (c.get("tasks", []) or []): + cand = selected_by_task.get(task_id) + if cand is None: + return False + current = float((cand.get("features", {}) or {}).get(fid, 0.0)) + if not _check_bound(current, op, rhs): + return False + else: + current = float(aggregated_qos.get(fid, 0.0)) + if not _check_bound(current, op, rhs): + return False + + elif kind == "DEPENDENCY": + dep_type = str(c.get("type", "")).upper() + tasks = [t for t in (c.get("tasks", []) or []) if isinstance(t, str)] + if len(tasks) < 2: + continue + providers: List[str] = [] + for task_id in tasks: + cand = selected_by_task.get(task_id) + if cand is None: + return False + providers.append(str(cand.get("provider_id", ""))) + + if dep_type == "SAME_PROVIDER": + if len(set(providers)) != 1: + return False + elif dep_type == "DIFFERENT_PROVIDER": + if len(set(providers)) != len(providers): + return False + + return True + + +def _build_fallback_binding(instance: Dict[str, Any]) -> Dict[str, str]: + tasks = [t["id"] for t in instance.get("tasks", [])] + by_task = _candidates_by_task(instance) + binding: Dict[str, str] = {} + shared_pid = "p_gen_shared" + + for task_id in tasks: + options = by_task.get(task_id, []) + if not options: + continue + shared = next((c for c in options if c.get("provider_id") == shared_pid), None) + chosen = shared or options[0] + binding[task_id] = str(chosen["id"]) + + if len(tasks) >= 3: + pivot = tasks[-1] + options = by_task.get(pivot, []) + current = binding.get(pivot) + current_provider = None + if current is not None: + current_provider = str(_candidate_lookup(instance).get(current, {}).get("provider_id", "")) + alternative = next( + (c for c in options if str(c.get("provider_id", "")) != current_provider), + None, + ) + if alternative is not None: + binding[pivot] = str(alternative["id"]) + + return binding + + +def _find_hard_feasible_binding(instance: Dict[str, Any], rng: random.Random, attempts: int = 4000) -> Dict[str, str]: + tasks = [t["id"] for t in instance.get("tasks", [])] + by_task = _candidates_by_task(instance) + if any(not by_task.get(tid) for tid in tasks): + return {} + + fallback = _build_fallback_binding(instance) + if fallback and _binding_satisfies_hard_constraints(instance, fallback): + return fallback + + for _ in range(attempts): + binding = { + task_id: str(rng.choice(by_task[task_id])["id"]) + for task_id in tasks + } + if _binding_satisfies_hard_constraints(instance, binding): + return binding + + return fallback + + +def _find_same_provider_tasks(binding: Dict[str, str], instance: Dict[str, Any]) -> List[str]: + by_id = _candidate_lookup(instance) + tasks = sorted(binding.keys()) + provider_by_task = { + t: str((by_id.get(binding[t], {}) or {}).get("provider_id", "")) + for t in tasks + } + groups: Dict[str, List[str]] = {} + for task_id, pid in provider_by_task.items(): + groups.setdefault(pid, []).append(task_id) + best = [] + for group in groups.values(): + if len(group) >= 2 and len(group) > len(best): + best = sorted(group) + return best[:2] + + +def _find_different_provider_tasks(binding: Dict[str, str], instance: Dict[str, Any]) -> List[str]: + by_id = _candidate_lookup(instance) + tasks = sorted(binding.keys()) + provider_by_task = { + t: str((by_id.get(binding[t], {}) or {}).get("provider_id", "")) + for t in tasks + } + for a, b in itertools.combinations(tasks, 2): + if provider_by_task.get(a) != provider_by_task.get(b): + return [a, b] + return [] + + +def _pick_attribute_for_constraints(feature_defs: List[Dict[str, Any]]) -> str: + # Prefer non-ratio MINIMIZE attributes for bounds; else fall back. + for f in feature_defs: + if f.get("direction") == "MINIMIZE": + return f["id"] + return feature_defs[0]["id"] + + +def generate_additional_constraints( + instance: Dict[str, Any], hard: bool, rng: random.Random +) -> List[Dict[str, Any]]: + """Add schema-consistent constraints that are feasible by construction. + + We first obtain a witness binding that satisfies all *existing hard* constraints, + then derive GLOBAL/LOCAL/DEPENDENCY constraints from that witness. + """ + + tasks = [t["id"] for t in instance.get("tasks", [])] + feature_defs = instance.get("features", []) + if not tasks or not feature_defs: + return [] + + existing_ids = _id_set(instance.get("constraints", [])) + fmap = _feature_map(instance) + by_id = _candidate_lookup(instance) + constraints: List[Dict[str, Any]] = [] + + binding = _find_hard_feasible_binding(instance, rng) + if not binding: + return constraints + + aggregated = _compute_aggregated_qos(instance, binding) + + # 1) GLOBAL ATTRIBUTE_BOUND from witness aggregated value. + global_attr = _pick_attribute_for_constraints(feature_defs) + gdef = fmap[global_attr] + gdir = str(gdef.get("direction", "MINIMIZE")) + gvalue = float(aggregated.get(global_attr, 0.0)) + gmn, gmx = _range_for_feature(gdef) + constraints.append( + { + "id": _unique_id(f"gen_c_global_{global_attr}_", existing_ids), + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": global_attr, + "op": "<=" if gdir == "MINIMIZE" else ">=", + "value": round(gvalue, 6 if gmx <= 1.0 else 2), + "hard": hard, + } + ) + + # 2) LOCAL ATTRIBUTE_BOUND from witness selected candidate feature. + local_task = sorted(binding.keys())[0] + local_attr = feature_defs[min(1, len(feature_defs) - 1)]["id"] + ldef = fmap[local_attr] + ldir = str(ldef.get("direction", "MINIMIZE")) + selected_cand = by_id.get(binding[local_task], {}) + lraw = float((selected_cand.get("features", {}) or {}).get(local_attr, 0.0)) + lmn, lmx = _range_for_feature(ldef) + lvalue = _clamp(lraw, lmn, lmx) if lmn <= lmx else lraw + constraints.append( + { + "id": _unique_id(f"gen_c_local_{local_task}_{local_attr}_", existing_ids), + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [local_task], + "attribute_id": local_attr, + "op": "<=" if ldir == "MINIMIZE" else ">=", + "value": round(lvalue, 6 if lmx <= 1.0 else 2), + "hard": hard, + } + ) + + # 3) SAME_PROVIDER dependency from witness. + same_tasks = _find_same_provider_tasks(binding, instance) + if len(same_tasks) >= 2: + constraints.append( + { + "id": _unique_id("gen_c_dep_same_", existing_ids), + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": same_tasks, + "hard": hard, + } + ) + + # 4) DIFFERENT_PROVIDER dependency from witness. + diff_tasks = _find_different_provider_tasks(binding, instance) + if len(diff_tasks) >= 2: + constraints.append( + { + "id": _unique_id("gen_c_dep_diff_", existing_ids), + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": diff_tasks, + "hard": hard, + } + ) + + return constraints + +def _normalize_weights_2dp_sum1(targets: List[str], raw_weights: Dict[str, float]) -> Dict[str, float]: + if not targets: return {} + values = [max(float(raw_weights.get(t, 0.0)), 0.0) for t in targets] + total = sum(values) + if total <= 0: + values = [1.0] * len(targets) + total = float(len(targets)) + + exact_cents = [(v / total) * 100.0 for v in values] + base_cents = [int(math.floor(c)) for c in exact_cents] + remainders = [c - b for c, b in zip(exact_cents, base_cents)] + cents = base_cents[:] + leftover = 100 - sum(cents) + + if leftover > 0: + indices = sorted(range(len(targets)), key=lambda i: remainders[i], reverse=True) + for i in indices[:leftover]: cents[i] += 1 + elif leftover < 0: + indices = sorted(range(len(targets)), key=lambda i: remainders[i]) + for i in indices: + if leftover == 0: break + if cents[i] > 0: + cents[i] -= 1 + leftover += 1 + + return {t: round(c / 100.0, 2) for t, c in zip(targets, cents)} + +def _objective_mono_one(all_features: List[str]) -> Dict[str, Any]: + target = all_features[0] + return { + "type": "MONO", + "targets": [target], + "weights": {target: 1.0}, + "weights_sum_to_one": True, + } + + +def _objective_mono_utility(all_features: List[str]) -> Dict[str, Any]: + # Utility / weighted sum across multiple attributes (keep type MONO as requested). + targets = list(all_features) + weights = _normalize_weights_2dp_sum1(targets, {t: 1.0 for t in targets}) + return { + "type": "MONO", + "targets": targets, + "weights": weights, + "weights_sum_to_one": True, + } + + +def _objective_multi(all_features: List[str]) -> Dict[str, Any]: + n = 3 if len(all_features) >= 3 else 2 + targets = all_features[:n] + return { + "type": "MULTI", + "targets": targets, + "weights": _normalize_weights_2dp_sum1(targets, {t: 1.0 for t in targets}), + "weights_sum_to_one": True, + } + + +def _objective_many(all_features: List[str]) -> Dict[str, Any]: + targets = list(all_features) + if len(targets) < 3: + # Should not happen after feature expansion, but keep schema-valid. + targets = (targets * 3)[:3] + return { + "type": "MANY", + "targets": targets, + "weights": _normalize_weights_2dp_sum1(targets, {t: 1.0 for t in targets}), + "weights_sum_to_one": True, + } + + +def _now_iso() -> str: + return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z") + + +def _seed_for(*parts: str) -> int: + # Stable across runs; avoid Python's randomized hash. + s = "|".join(parts) + h = 2166136261 + for ch in s: + h ^= ord(ch) + h = (h * 16777619) & 0xFFFFFFFF + return int((h + RANDOM_SEED) & 0xFFFFFFFF) + + +def build_scaled_base_instance(base: Dict[str, Any]) -> Dict[str, Any]: + instance = copy.deepcopy(base) + + # Ensure optional keys exist. + instance.setdefault("constraints", []) + + # Expand features/providers/candidates deterministically. + rng = random.Random(_seed_for(instance["metadata"]["id"], "scale")) + expand_providers(instance, EXTRA_PROVIDERS_PER_SCENARIO) + expand_features(instance, EXTRA_FEATURES_PER_SCENARIO) + ensure_aggregation_policies_complete(instance) + ensure_binding_space_gt(instance, TARGET_BINDING_SPACE, rng) + return instance + + +def build_variant( + base_scaled: Dict[str, Any], + objective: Dict[str, Any], + hard_constraints: bool, + variant_suffix: str, +) -> Dict[str, Any]: + inst = copy.deepcopy(base_scaled) + inst["objective"] = objective + + # Add additional constraints (hard first); then soften if needed. + rng = random.Random(_seed_for(base_scaled["metadata"]["id"], variant_suffix, "constraints")) + additional = generate_additional_constraints(inst, hard=True, rng=rng) + inst_constraints = list(inst.get("constraints", [])) + additional + + if hard_constraints: + inst["constraints"] = inst_constraints + constraint_mode = "hard" + else: + softened: List[Dict[str, Any]] = [] + for c in inst_constraints: + c2 = copy.deepcopy(c) + c2["hard"] = False + softened.append(c2) + inst["constraints"] = softened + constraint_mode = "soft" + + # Update metadata. + base_id = base_scaled["metadata"]["id"].split("_scaled_")[0] + inst["metadata"] = copy.deepcopy(base_scaled.get("metadata", {})) + inst["metadata"]["id"] = f"{base_id}_{variant_suffix}_{constraint_mode}" + inst["metadata"]["name"] = f"{inst['metadata'].get('name', base_id)} [{variant_suffix}, {constraint_mode}]" + inst["metadata"]["created_at"] = _now_iso() + + return inst + +def main(): + output_dir = DEFAULT_OUTPUT_DIR + output_dir.mkdir(parents=True, exist_ok=True) + + print(f"Using seed: {RANDOM_SEED}") + + for filename in SCENARIOS: + try: + base_instance = load_scenario(filename) + except FileNotFoundError: + print(f"Scenario not found: {filename}") + continue + + base_id = base_instance["metadata"]["id"] + print(f"Processing {base_id}...") + + scaled = build_scaled_base_instance(base_instance) + all_features = [f["id"] for f in scaled.get("features", [])] + # Deterministic ordering for objective selection. + all_features = sorted(all_features) + + variants: List[Tuple[str, Dict[str, Any]]] = [ + ("mono_one", _objective_mono_one(all_features)), + ("mono_utility", _objective_mono_utility(all_features)), + ("multi", _objective_multi(all_features)), + ("many", _objective_many(all_features)), + ] + + for variant_name, objective in variants: + # Hard + inst_hard = build_variant( + scaled, + objective, + hard_constraints=True, + variant_suffix=variant_name, + ) + save_instance(inst_hard, output_dir, f"{base_id}_{variant_name}_hard.json") + + # Soft + inst_soft = build_variant( + scaled, + objective, + hard_constraints=False, + variant_suffix=variant_name, + ) + save_instance(inst_soft, output_dir, f"{base_id}_{variant_name}_soft.json") + +if __name__ == "__main__": + main() diff --git a/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_many_hard.json b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_many_hard.json new file mode 100644 index 0000000..b636c62 --- /dev/null +++ b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_many_hard.json @@ -0,0 +1,1278 @@ +{ + "metadata": { + "id": "benatallah2002-selfserv-travel-solution-cts-itas_many_hard", + "name": "Travel Solution (Benatallah et al. 2002) [many, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from the SELF-SERV running example (CTS and ITAS statecharts). QoS values and branch probabilities are illustrative because the paper does not provide numeric QoS.", + "paper": { + "title": "Declarative Compositionand Peer-to-PeerProvisioning of Dynamic WebServices", + "authors": "B. Benatallah et al.", + "year": 2002, + "doi": "10.5555/876875.878987" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Total price charged to customer", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "availability", + "name": "Probability the service invocation succeeds", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_attractions_a", + "name": "AttractionsSearch Provider A" + }, + { + "id": "p_attractions_b", + "name": "AttractionsSearch Provider B" + }, + { + "id": "p_dom_air_a", + "name": "Domestic Airline A" + }, + { + "id": "p_dom_air_b", + "name": "Domestic Airline B" + }, + { + "id": "p_int_air_a", + "name": "International Airline A" + }, + { + "id": "p_int_air_b", + "name": "International Airline B" + }, + { + "id": "p_ins_a", + "name": "Travel Insurance Co. A" + }, + { + "id": "p_ins_b", + "name": "Travel Insurance Co. B" + }, + { + "id": "p_hotel_a", + "name": "Accommodation Provider A" + }, + { + "id": "p_hotel_b", + "name": "Accommodation Provider B" + }, + { + "id": "p_car_a", + "name": "Car Rental Provider A" + }, + { + "id": "p_car_b", + "name": "Car Rental Provider B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_attractions_search", + "name": "Attractions Search (ASS.getAttractions)" + }, + { + "id": "t_flight_booking_domestic", + "name": "Domestic Flight Booking (DFBS.booking)" + }, + { + "id": "t_flight_booking_international", + "name": "International Flight Booking (IFBS.booking)" + }, + { + "id": "t_travel_insurance", + "name": "Travel Insurance (TIS.getInsurance)" + }, + { + "id": "t_accommodation_booking", + "name": "Accommodation Booking (ABS.booking)" + }, + { + "id": "t_car_rental_booking", + "name": "Car Rental Booking (CRS.booking)" + } + ], + "candidates": [ + { + "id": "svc_ass_1", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_a", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 180, + "cost_usd": 0, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ass_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 120, + "cost_usd": 5, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_a", + "name": "DFBS.booking", + "features": { + "latency_ms": 650, + "cost_usd": 420, + "availability": 0.985, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_b", + "name": "DFBS.booking", + "features": { + "latency_ms": 520, + "cost_usd": 460, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking", + "features": { + "latency_ms": 780, + "cost_usd": 820, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_b", + "name": "IFBS.booking", + "features": { + "latency_ms": 610, + "cost_usd": 900, + "availability": 0.988, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_1", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 240, + "cost_usd": 55, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_2", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 190, + "cost_usd": 70, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_a", + "name": "ABS.booking", + "features": { + "latency_ms": 430, + "cost_usd": 950, + "availability": 0.992, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_b", + "name": "ABS.booking", + "features": { + "latency_ms": 350, + "cost_usd": 1100, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_a", + "name": "CRS.booking", + "features": { + "latency_ms": 310, + "cost_usd": 260, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_b", + "name": "CRS.booking", + "features": { + "latency_ms": 260, + "cost_usd": 320, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_attractions_search_gen_1", + "task_id": "t_attractions_search", + "provider_id": "p_gen_shared", + "name": "ASS.getAttractions (Gen Shared)", + "features": { + "latency_ms": 180.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.57, + "gen_feat_2": 0.493935, + "gen_feat_3": 485.71 + } + }, + { + "id": "t_flight_booking_domestic_gen_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_shared", + "name": "DFBS.booking (Gen Shared)", + "features": { + "latency_ms": 647.32, + "cost_usd": 411.46, + "availability": 0.979506, + "gen_feat_1": 505.68, + "gen_feat_2": 0.506905, + "gen_feat_3": 510.18 + } + }, + { + "id": "t_flight_booking_international_gen_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_shared", + "name": "IFBS.booking (Gen Shared)", + "features": { + "latency_ms": 759.62, + "cost_usd": 814.07, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.503149, + "gen_feat_3": 501.18 + } + }, + { + "id": "t_travel_insurance_gen_1", + "task_id": "t_travel_insurance", + "provider_id": "p_gen_shared", + "name": "TIS.getInsurance (Gen Shared)", + "features": { + "latency_ms": 234.01, + "cost_usd": 55.73, + "availability": 0.994473, + "gen_feat_1": 505.2, + "gen_feat_2": 0.498515, + "gen_feat_3": 487.21 + } + }, + { + "id": "t_accommodation_booking_gen_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_shared", + "name": "ABS.booking (Gen Shared)", + "features": { + "latency_ms": 423.14, + "cost_usd": 927.58, + "availability": 0.985309, + "gen_feat_1": 494.62, + "gen_feat_2": 0.504056, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_car_rental_booking_gen_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_gen_shared", + "name": "CRS.booking (Gen Shared)", + "features": { + "latency_ms": 303.36, + "cost_usd": 252.45, + "availability": 0.962251, + "gen_feat_1": 502.73, + "gen_feat_2": 0.492905, + "gen_feat_3": 511.21 + } + }, + { + "id": "t_attractions_search_gen_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions (Gen p_attractions_b)", + "features": { + "latency_ms": 183.9, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.11, + "gen_feat_2": 0.507033, + "gen_feat_3": 506.35 + } + }, + { + "id": "t_attractions_search_gen_3", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_a", + "name": "ASS.getAttractions (Gen p_dom_air_a)", + "features": { + "latency_ms": 184.86, + "cost_usd": 0.0, + "availability": 0.973261, + "gen_feat_1": 512.0, + "gen_feat_2": 0.499623, + "gen_feat_3": 508.68 + } + }, + { + "id": "t_attractions_search_gen_4", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_b", + "name": "ASS.getAttractions (Gen p_dom_air_b)", + "features": { + "latency_ms": 177.98, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.492691, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_attractions_search_gen_5", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_a", + "name": "ASS.getAttractions (Gen p_int_air_a)", + "features": { + "latency_ms": 180.31, + "cost_usd": 0.0, + "availability": 0.975329, + "gen_feat_1": 511.15, + "gen_feat_2": 0.485867, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_attractions_search_gen_6", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_b", + "name": "ASS.getAttractions (Gen p_int_air_b)", + "features": { + "latency_ms": 178.35, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 491.67, + "gen_feat_2": 0.511467, + "gen_feat_3": 505.28 + } + }, + { + "id": "t_attractions_search_gen_7", + "task_id": "t_attractions_search", + "provider_id": "p_ins_a", + "name": "ASS.getAttractions (Gen p_ins_a)", + "features": { + "latency_ms": 183.13, + "cost_usd": 0.0, + "availability": 0.982652, + "gen_feat_1": 486.89, + "gen_feat_2": 0.493076, + "gen_feat_3": 489.66 + } + }, + { + "id": "t_attractions_search_gen_8", + "task_id": "t_attractions_search", + "provider_id": "p_ins_b", + "name": "ASS.getAttractions (Gen p_ins_b)", + "features": { + "latency_ms": 176.67, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.91, + "gen_feat_2": 0.510797, + "gen_feat_3": 494.78 + } + }, + { + "id": "t_flight_booking_domestic_gen_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_a", + "name": "DFBS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 631.95, + "cost_usd": 420.96, + "availability": 0.993293, + "gen_feat_1": 509.36, + "gen_feat_2": 0.48832, + "gen_feat_3": 493.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_3", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_b", + "name": "DFBS.booking (Gen p_hotel_b)", + "features": { + "latency_ms": 657.0, + "cost_usd": 410.51, + "availability": 1.0, + "gen_feat_1": 512.88, + "gen_feat_2": 0.494914, + "gen_feat_3": 493.16 + } + }, + { + "id": "t_flight_booking_domestic_gen_4", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_a", + "name": "DFBS.booking (Gen p_car_a)", + "features": { + "latency_ms": 662.74, + "cost_usd": 432.29, + "availability": 0.955965, + "gen_feat_1": 500.97, + "gen_feat_2": 0.486536, + "gen_feat_3": 491.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_5", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_b", + "name": "DFBS.booking (Gen p_car_b)", + "features": { + "latency_ms": 660.26, + "cost_usd": 422.73, + "availability": 1.0, + "gen_feat_1": 511.72, + "gen_feat_2": 0.496489, + "gen_feat_3": 514.27 + } + }, + { + "id": "t_flight_booking_domestic_gen_6", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_1", + "name": "DFBS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 638.86, + "cost_usd": 413.02, + "availability": 0.985773, + "gen_feat_1": 498.15, + "gen_feat_2": 0.488561, + "gen_feat_3": 503.45 + } + }, + { + "id": "t_flight_booking_domestic_gen_7", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_2", + "name": "DFBS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 641.08, + "cost_usd": 429.65, + "availability": 0.978204, + "gen_feat_1": 506.04, + "gen_feat_2": 0.496573, + "gen_feat_3": 510.36 + } + }, + { + "id": "t_flight_booking_domestic_gen_8", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_3", + "name": "DFBS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 664.71, + "cost_usd": 414.68, + "availability": 0.966781, + "gen_feat_1": 489.74, + "gen_feat_2": 0.487447, + "gen_feat_3": 486.76 + } + }, + { + "id": "t_flight_booking_international_gen_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_4", + "name": "IFBS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 802.29, + "cost_usd": 805.78, + "availability": 0.988419, + "gen_feat_1": 509.12, + "gen_feat_2": 0.493932, + "gen_feat_3": 494.56 + } + }, + { + "id": "t_flight_booking_international_gen_3", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_5", + "name": "IFBS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 785.65, + "cost_usd": 832.67, + "availability": 1.0, + "gen_feat_1": 498.69, + "gen_feat_2": 0.506699, + "gen_feat_3": 486.23 + } + }, + { + "id": "t_flight_booking_international_gen_4", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_a", + "name": "IFBS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 795.93, + "cost_usd": 844.09, + "availability": 0.963688, + "gen_feat_1": 492.63, + "gen_feat_2": 0.50024, + "gen_feat_3": 503.14 + } + }, + { + "id": "t_flight_booking_international_gen_5", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_b", + "name": "IFBS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 763.55, + "cost_usd": 806.59, + "availability": 0.973216, + "gen_feat_1": 490.91, + "gen_feat_2": 0.504181, + "gen_feat_3": 493.32 + } + }, + { + "id": "t_flight_booking_international_gen_6", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_a", + "name": "IFBS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 775.31, + "cost_usd": 813.89, + "availability": 1.0, + "gen_feat_1": 514.34, + "gen_feat_2": 0.490809, + "gen_feat_3": 502.88 + } + }, + { + "id": "t_flight_booking_international_gen_7", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_b", + "name": "IFBS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 774.09, + "cost_usd": 796.86, + "availability": 1.0, + "gen_feat_1": 509.97, + "gen_feat_2": 0.50639, + "gen_feat_3": 488.65 + } + }, + { + "id": "t_flight_booking_international_gen_8", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 802.89, + "cost_usd": 832.54, + "availability": 0.995867, + "gen_feat_1": 500.61, + "gen_feat_2": 0.492753, + "gen_feat_3": 489.35 + } + }, + { + "id": "t_travel_insurance_gen_2", + "task_id": "t_travel_insurance", + "provider_id": "p_int_air_b", + "name": "TIS.getInsurance (Gen p_int_air_b)", + "features": { + "latency_ms": 239.89, + "cost_usd": 54.54, + "availability": 0.978354, + "gen_feat_1": 504.59, + "gen_feat_2": 0.502031, + "gen_feat_3": 500.67 + } + }, + { + "id": "t_travel_insurance_gen_3", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance (Gen p_ins_a)", + "features": { + "latency_ms": 235.94, + "cost_usd": 55.24, + "availability": 1.0, + "gen_feat_1": 510.78, + "gen_feat_2": 0.49515, + "gen_feat_3": 514.3 + } + }, + { + "id": "t_travel_insurance_gen_4", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance (Gen p_ins_b)", + "features": { + "latency_ms": 239.19, + "cost_usd": 54.65, + "availability": 0.97242, + "gen_feat_1": 493.99, + "gen_feat_2": 0.507973, + "gen_feat_3": 491.39 + } + }, + { + "id": "t_travel_insurance_gen_5", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_a", + "name": "TIS.getInsurance (Gen p_hotel_a)", + "features": { + "latency_ms": 237.46, + "cost_usd": 55.4, + "availability": 1.0, + "gen_feat_1": 502.98, + "gen_feat_2": 0.490074, + "gen_feat_3": 504.05 + } + }, + { + "id": "t_travel_insurance_gen_6", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_b", + "name": "TIS.getInsurance (Gen p_hotel_b)", + "features": { + "latency_ms": 246.8, + "cost_usd": 55.95, + "availability": 0.997177, + "gen_feat_1": 498.91, + "gen_feat_2": 0.494214, + "gen_feat_3": 502.98 + } + }, + { + "id": "t_travel_insurance_gen_7", + "task_id": "t_travel_insurance", + "provider_id": "p_car_a", + "name": "TIS.getInsurance (Gen p_car_a)", + "features": { + "latency_ms": 246.54, + "cost_usd": 54.9, + "availability": 0.99944, + "gen_feat_1": 492.97, + "gen_feat_2": 0.512985, + "gen_feat_3": 497.1 + } + }, + { + "id": "t_travel_insurance_gen_8", + "task_id": "t_travel_insurance", + "provider_id": "p_car_b", + "name": "TIS.getInsurance (Gen p_car_b)", + "features": { + "latency_ms": 245.14, + "cost_usd": 53.91, + "availability": 1.0, + "gen_feat_1": 507.6, + "gen_feat_2": 0.491973, + "gen_feat_3": 489.42 + } + }, + { + "id": "t_accommodation_booking_gen_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_1", + "name": "ABS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 417.7, + "cost_usd": 957.65, + "availability": 1.0, + "gen_feat_1": 491.17, + "gen_feat_2": 0.487995, + "gen_feat_3": 496.04 + } + }, + { + "id": "t_accommodation_booking_gen_3", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_2", + "name": "ABS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 435.3, + "cost_usd": 943.55, + "availability": 0.98734, + "gen_feat_1": 490.66, + "gen_feat_2": 0.512804, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_accommodation_booking_gen_4", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_3", + "name": "ABS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 424.85, + "cost_usd": 946.36, + "availability": 0.983088, + "gen_feat_1": 490.8, + "gen_feat_2": 0.498715, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_accommodation_booking_gen_5", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_4", + "name": "ABS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 437.83, + "cost_usd": 931.98, + "availability": 0.989306, + "gen_feat_1": 486.79, + "gen_feat_2": 0.511194, + "gen_feat_3": 509.55 + } + }, + { + "id": "t_accommodation_booking_gen_6", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_5", + "name": "ABS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 441.94, + "cost_usd": 938.72, + "availability": 1.0, + "gen_feat_1": 500.85, + "gen_feat_2": 0.494949, + "gen_feat_3": 494.14 + } + }, + { + "id": "t_accommodation_booking_gen_7", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_a", + "name": "ABS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 438.16, + "cost_usd": 938.79, + "availability": 1.0, + "gen_feat_1": 485.27, + "gen_feat_2": 0.498913, + "gen_feat_3": 487.12 + } + }, + { + "id": "t_accommodation_booking_gen_8", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_b", + "name": "ABS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 418.07, + "cost_usd": 922.82, + "availability": 1.0, + "gen_feat_1": 497.81, + "gen_feat_2": 0.502515, + "gen_feat_3": 509.16 + } + }, + { + "id": "t_car_rental_booking_gen_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_a", + "name": "CRS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 312.13, + "cost_usd": 261.53, + "availability": 1.0, + "gen_feat_1": 512.64, + "gen_feat_2": 0.496089, + "gen_feat_3": 504.19 + } + }, + { + "id": "t_car_rental_booking_gen_3", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_b", + "name": "CRS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 313.91, + "cost_usd": 257.49, + "availability": 0.98681, + "gen_feat_1": 512.87, + "gen_feat_2": 0.505241, + "gen_feat_3": 507.29 + } + }, + { + "id": "t_car_rental_booking_gen_4", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_a", + "name": "CRS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 302.5, + "cost_usd": 253.26, + "availability": 0.988174, + "gen_feat_1": 486.1, + "gen_feat_2": 0.485054, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_car_rental_booking_gen_5", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_b", + "name": "CRS.booking (Gen p_int_air_b)", + "features": { + "latency_ms": 318.31, + "cost_usd": 266.75, + "availability": 0.978032, + "gen_feat_1": 497.95, + "gen_feat_2": 0.49628, + "gen_feat_3": 508.32 + } + }, + { + "id": "t_car_rental_booking_gen_6", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_a", + "name": "CRS.booking (Gen p_ins_a)", + "features": { + "latency_ms": 315.37, + "cost_usd": 257.45, + "availability": 0.991843, + "gen_feat_1": 510.59, + "gen_feat_2": 0.501464, + "gen_feat_3": 495.6 + } + }, + { + "id": "t_car_rental_booking_gen_7", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_b", + "name": "CRS.booking (Gen p_ins_b)", + "features": { + "latency_ms": 311.72, + "cost_usd": 255.51, + "availability": 0.984838, + "gen_feat_1": 498.99, + "gen_feat_2": 0.505672, + "gen_feat_3": 506.54 + } + }, + { + "id": "t_car_rental_booking_gen_8", + "task_id": "t_car_rental_booking", + "provider_id": "p_hotel_a", + "name": "CRS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 306.59, + "cost_usd": 258.27, + "availability": 1.0, + "gen_feat_1": 512.19, + "gen_feat_2": 0.506375, + "gen_feat_3": 513.91 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_parallel", + "kind": "AND", + "children": [ + { + "id": "n_as", + "kind": "TASK", + "task_id": "t_attractions_search" + }, + { + "id": "n_booking_flow", + "kind": "SEQ", + "children": [ + { + "id": "n_flight_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.6, + "child": { + "id": "n_dfb", + "kind": "TASK", + "task_id": "t_flight_booking_domestic" + } + }, + { + "p": 0.4, + "child": { + "id": "n_intl_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_ifb", + "kind": "TASK", + "task_id": "t_flight_booking_international" + }, + { + "id": "n_ti", + "kind": "TASK", + "task_id": "t_travel_insurance" + } + ] + } + } + ] + }, + { + "id": "n_ab", + "kind": "TASK", + "task_id": "t_accommodation_booking" + } + ] + } + ] + }, + { + "id": "n_car_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.3, + "child": { + "id": "n_cr", + "kind": "TASK", + "task_id": "t_car_rental_booking" + } + }, + { + "p": 0.7, + "child": { + "id": "n_no_car", + "kind": "ELEMENT", + "description": "Skip car rental (represents the near(...) branch)" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MANY", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1301.98, + "hard": true + }, + { + "id": "gen_c_local_t_accommodation_booking_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_accommodation_booking" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 927.58, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_attractions_search" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_car_rental_booking" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_many_soft.json b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_many_soft.json new file mode 100644 index 0000000..3be7c54 --- /dev/null +++ b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_many_soft.json @@ -0,0 +1,1278 @@ +{ + "metadata": { + "id": "benatallah2002-selfserv-travel-solution-cts-itas_many_soft", + "name": "Travel Solution (Benatallah et al. 2002) [many, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from the SELF-SERV running example (CTS and ITAS statecharts). QoS values and branch probabilities are illustrative because the paper does not provide numeric QoS.", + "paper": { + "title": "Declarative Compositionand Peer-to-PeerProvisioning of Dynamic WebServices", + "authors": "B. Benatallah et al.", + "year": 2002, + "doi": "10.5555/876875.878987" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Total price charged to customer", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "availability", + "name": "Probability the service invocation succeeds", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_attractions_a", + "name": "AttractionsSearch Provider A" + }, + { + "id": "p_attractions_b", + "name": "AttractionsSearch Provider B" + }, + { + "id": "p_dom_air_a", + "name": "Domestic Airline A" + }, + { + "id": "p_dom_air_b", + "name": "Domestic Airline B" + }, + { + "id": "p_int_air_a", + "name": "International Airline A" + }, + { + "id": "p_int_air_b", + "name": "International Airline B" + }, + { + "id": "p_ins_a", + "name": "Travel Insurance Co. A" + }, + { + "id": "p_ins_b", + "name": "Travel Insurance Co. B" + }, + { + "id": "p_hotel_a", + "name": "Accommodation Provider A" + }, + { + "id": "p_hotel_b", + "name": "Accommodation Provider B" + }, + { + "id": "p_car_a", + "name": "Car Rental Provider A" + }, + { + "id": "p_car_b", + "name": "Car Rental Provider B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_attractions_search", + "name": "Attractions Search (ASS.getAttractions)" + }, + { + "id": "t_flight_booking_domestic", + "name": "Domestic Flight Booking (DFBS.booking)" + }, + { + "id": "t_flight_booking_international", + "name": "International Flight Booking (IFBS.booking)" + }, + { + "id": "t_travel_insurance", + "name": "Travel Insurance (TIS.getInsurance)" + }, + { + "id": "t_accommodation_booking", + "name": "Accommodation Booking (ABS.booking)" + }, + { + "id": "t_car_rental_booking", + "name": "Car Rental Booking (CRS.booking)" + } + ], + "candidates": [ + { + "id": "svc_ass_1", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_a", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 180, + "cost_usd": 0, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ass_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 120, + "cost_usd": 5, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_a", + "name": "DFBS.booking", + "features": { + "latency_ms": 650, + "cost_usd": 420, + "availability": 0.985, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_b", + "name": "DFBS.booking", + "features": { + "latency_ms": 520, + "cost_usd": 460, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking", + "features": { + "latency_ms": 780, + "cost_usd": 820, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_b", + "name": "IFBS.booking", + "features": { + "latency_ms": 610, + "cost_usd": 900, + "availability": 0.988, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_1", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 240, + "cost_usd": 55, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_2", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 190, + "cost_usd": 70, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_a", + "name": "ABS.booking", + "features": { + "latency_ms": 430, + "cost_usd": 950, + "availability": 0.992, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_b", + "name": "ABS.booking", + "features": { + "latency_ms": 350, + "cost_usd": 1100, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_a", + "name": "CRS.booking", + "features": { + "latency_ms": 310, + "cost_usd": 260, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_b", + "name": "CRS.booking", + "features": { + "latency_ms": 260, + "cost_usd": 320, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_attractions_search_gen_1", + "task_id": "t_attractions_search", + "provider_id": "p_gen_shared", + "name": "ASS.getAttractions (Gen Shared)", + "features": { + "latency_ms": 180.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.57, + "gen_feat_2": 0.493935, + "gen_feat_3": 485.71 + } + }, + { + "id": "t_flight_booking_domestic_gen_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_shared", + "name": "DFBS.booking (Gen Shared)", + "features": { + "latency_ms": 647.32, + "cost_usd": 411.46, + "availability": 0.979506, + "gen_feat_1": 505.68, + "gen_feat_2": 0.506905, + "gen_feat_3": 510.18 + } + }, + { + "id": "t_flight_booking_international_gen_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_shared", + "name": "IFBS.booking (Gen Shared)", + "features": { + "latency_ms": 759.62, + "cost_usd": 814.07, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.503149, + "gen_feat_3": 501.18 + } + }, + { + "id": "t_travel_insurance_gen_1", + "task_id": "t_travel_insurance", + "provider_id": "p_gen_shared", + "name": "TIS.getInsurance (Gen Shared)", + "features": { + "latency_ms": 234.01, + "cost_usd": 55.73, + "availability": 0.994473, + "gen_feat_1": 505.2, + "gen_feat_2": 0.498515, + "gen_feat_3": 487.21 + } + }, + { + "id": "t_accommodation_booking_gen_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_shared", + "name": "ABS.booking (Gen Shared)", + "features": { + "latency_ms": 423.14, + "cost_usd": 927.58, + "availability": 0.985309, + "gen_feat_1": 494.62, + "gen_feat_2": 0.504056, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_car_rental_booking_gen_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_gen_shared", + "name": "CRS.booking (Gen Shared)", + "features": { + "latency_ms": 303.36, + "cost_usd": 252.45, + "availability": 0.962251, + "gen_feat_1": 502.73, + "gen_feat_2": 0.492905, + "gen_feat_3": 511.21 + } + }, + { + "id": "t_attractions_search_gen_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions (Gen p_attractions_b)", + "features": { + "latency_ms": 183.9, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.11, + "gen_feat_2": 0.507033, + "gen_feat_3": 506.35 + } + }, + { + "id": "t_attractions_search_gen_3", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_a", + "name": "ASS.getAttractions (Gen p_dom_air_a)", + "features": { + "latency_ms": 184.86, + "cost_usd": 0.0, + "availability": 0.973261, + "gen_feat_1": 512.0, + "gen_feat_2": 0.499623, + "gen_feat_3": 508.68 + } + }, + { + "id": "t_attractions_search_gen_4", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_b", + "name": "ASS.getAttractions (Gen p_dom_air_b)", + "features": { + "latency_ms": 177.98, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.492691, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_attractions_search_gen_5", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_a", + "name": "ASS.getAttractions (Gen p_int_air_a)", + "features": { + "latency_ms": 180.31, + "cost_usd": 0.0, + "availability": 0.975329, + "gen_feat_1": 511.15, + "gen_feat_2": 0.485867, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_attractions_search_gen_6", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_b", + "name": "ASS.getAttractions (Gen p_int_air_b)", + "features": { + "latency_ms": 178.35, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 491.67, + "gen_feat_2": 0.511467, + "gen_feat_3": 505.28 + } + }, + { + "id": "t_attractions_search_gen_7", + "task_id": "t_attractions_search", + "provider_id": "p_ins_a", + "name": "ASS.getAttractions (Gen p_ins_a)", + "features": { + "latency_ms": 183.13, + "cost_usd": 0.0, + "availability": 0.982652, + "gen_feat_1": 486.89, + "gen_feat_2": 0.493076, + "gen_feat_3": 489.66 + } + }, + { + "id": "t_attractions_search_gen_8", + "task_id": "t_attractions_search", + "provider_id": "p_ins_b", + "name": "ASS.getAttractions (Gen p_ins_b)", + "features": { + "latency_ms": 176.67, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.91, + "gen_feat_2": 0.510797, + "gen_feat_3": 494.78 + } + }, + { + "id": "t_flight_booking_domestic_gen_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_a", + "name": "DFBS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 631.95, + "cost_usd": 420.96, + "availability": 0.993293, + "gen_feat_1": 509.36, + "gen_feat_2": 0.48832, + "gen_feat_3": 493.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_3", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_b", + "name": "DFBS.booking (Gen p_hotel_b)", + "features": { + "latency_ms": 657.0, + "cost_usd": 410.51, + "availability": 1.0, + "gen_feat_1": 512.88, + "gen_feat_2": 0.494914, + "gen_feat_3": 493.16 + } + }, + { + "id": "t_flight_booking_domestic_gen_4", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_a", + "name": "DFBS.booking (Gen p_car_a)", + "features": { + "latency_ms": 662.74, + "cost_usd": 432.29, + "availability": 0.955965, + "gen_feat_1": 500.97, + "gen_feat_2": 0.486536, + "gen_feat_3": 491.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_5", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_b", + "name": "DFBS.booking (Gen p_car_b)", + "features": { + "latency_ms": 660.26, + "cost_usd": 422.73, + "availability": 1.0, + "gen_feat_1": 511.72, + "gen_feat_2": 0.496489, + "gen_feat_3": 514.27 + } + }, + { + "id": "t_flight_booking_domestic_gen_6", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_1", + "name": "DFBS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 638.86, + "cost_usd": 413.02, + "availability": 0.985773, + "gen_feat_1": 498.15, + "gen_feat_2": 0.488561, + "gen_feat_3": 503.45 + } + }, + { + "id": "t_flight_booking_domestic_gen_7", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_2", + "name": "DFBS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 641.08, + "cost_usd": 429.65, + "availability": 0.978204, + "gen_feat_1": 506.04, + "gen_feat_2": 0.496573, + "gen_feat_3": 510.36 + } + }, + { + "id": "t_flight_booking_domestic_gen_8", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_3", + "name": "DFBS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 664.71, + "cost_usd": 414.68, + "availability": 0.966781, + "gen_feat_1": 489.74, + "gen_feat_2": 0.487447, + "gen_feat_3": 486.76 + } + }, + { + "id": "t_flight_booking_international_gen_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_4", + "name": "IFBS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 802.29, + "cost_usd": 805.78, + "availability": 0.988419, + "gen_feat_1": 509.12, + "gen_feat_2": 0.493932, + "gen_feat_3": 494.56 + } + }, + { + "id": "t_flight_booking_international_gen_3", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_5", + "name": "IFBS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 785.65, + "cost_usd": 832.67, + "availability": 1.0, + "gen_feat_1": 498.69, + "gen_feat_2": 0.506699, + "gen_feat_3": 486.23 + } + }, + { + "id": "t_flight_booking_international_gen_4", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_a", + "name": "IFBS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 795.93, + "cost_usd": 844.09, + "availability": 0.963688, + "gen_feat_1": 492.63, + "gen_feat_2": 0.50024, + "gen_feat_3": 503.14 + } + }, + { + "id": "t_flight_booking_international_gen_5", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_b", + "name": "IFBS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 763.55, + "cost_usd": 806.59, + "availability": 0.973216, + "gen_feat_1": 490.91, + "gen_feat_2": 0.504181, + "gen_feat_3": 493.32 + } + }, + { + "id": "t_flight_booking_international_gen_6", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_a", + "name": "IFBS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 775.31, + "cost_usd": 813.89, + "availability": 1.0, + "gen_feat_1": 514.34, + "gen_feat_2": 0.490809, + "gen_feat_3": 502.88 + } + }, + { + "id": "t_flight_booking_international_gen_7", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_b", + "name": "IFBS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 774.09, + "cost_usd": 796.86, + "availability": 1.0, + "gen_feat_1": 509.97, + "gen_feat_2": 0.50639, + "gen_feat_3": 488.65 + } + }, + { + "id": "t_flight_booking_international_gen_8", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 802.89, + "cost_usd": 832.54, + "availability": 0.995867, + "gen_feat_1": 500.61, + "gen_feat_2": 0.492753, + "gen_feat_3": 489.35 + } + }, + { + "id": "t_travel_insurance_gen_2", + "task_id": "t_travel_insurance", + "provider_id": "p_int_air_b", + "name": "TIS.getInsurance (Gen p_int_air_b)", + "features": { + "latency_ms": 239.89, + "cost_usd": 54.54, + "availability": 0.978354, + "gen_feat_1": 504.59, + "gen_feat_2": 0.502031, + "gen_feat_3": 500.67 + } + }, + { + "id": "t_travel_insurance_gen_3", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance (Gen p_ins_a)", + "features": { + "latency_ms": 235.94, + "cost_usd": 55.24, + "availability": 1.0, + "gen_feat_1": 510.78, + "gen_feat_2": 0.49515, + "gen_feat_3": 514.3 + } + }, + { + "id": "t_travel_insurance_gen_4", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance (Gen p_ins_b)", + "features": { + "latency_ms": 239.19, + "cost_usd": 54.65, + "availability": 0.97242, + "gen_feat_1": 493.99, + "gen_feat_2": 0.507973, + "gen_feat_3": 491.39 + } + }, + { + "id": "t_travel_insurance_gen_5", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_a", + "name": "TIS.getInsurance (Gen p_hotel_a)", + "features": { + "latency_ms": 237.46, + "cost_usd": 55.4, + "availability": 1.0, + "gen_feat_1": 502.98, + "gen_feat_2": 0.490074, + "gen_feat_3": 504.05 + } + }, + { + "id": "t_travel_insurance_gen_6", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_b", + "name": "TIS.getInsurance (Gen p_hotel_b)", + "features": { + "latency_ms": 246.8, + "cost_usd": 55.95, + "availability": 0.997177, + "gen_feat_1": 498.91, + "gen_feat_2": 0.494214, + "gen_feat_3": 502.98 + } + }, + { + "id": "t_travel_insurance_gen_7", + "task_id": "t_travel_insurance", + "provider_id": "p_car_a", + "name": "TIS.getInsurance (Gen p_car_a)", + "features": { + "latency_ms": 246.54, + "cost_usd": 54.9, + "availability": 0.99944, + "gen_feat_1": 492.97, + "gen_feat_2": 0.512985, + "gen_feat_3": 497.1 + } + }, + { + "id": "t_travel_insurance_gen_8", + "task_id": "t_travel_insurance", + "provider_id": "p_car_b", + "name": "TIS.getInsurance (Gen p_car_b)", + "features": { + "latency_ms": 245.14, + "cost_usd": 53.91, + "availability": 1.0, + "gen_feat_1": 507.6, + "gen_feat_2": 0.491973, + "gen_feat_3": 489.42 + } + }, + { + "id": "t_accommodation_booking_gen_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_1", + "name": "ABS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 417.7, + "cost_usd": 957.65, + "availability": 1.0, + "gen_feat_1": 491.17, + "gen_feat_2": 0.487995, + "gen_feat_3": 496.04 + } + }, + { + "id": "t_accommodation_booking_gen_3", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_2", + "name": "ABS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 435.3, + "cost_usd": 943.55, + "availability": 0.98734, + "gen_feat_1": 490.66, + "gen_feat_2": 0.512804, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_accommodation_booking_gen_4", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_3", + "name": "ABS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 424.85, + "cost_usd": 946.36, + "availability": 0.983088, + "gen_feat_1": 490.8, + "gen_feat_2": 0.498715, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_accommodation_booking_gen_5", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_4", + "name": "ABS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 437.83, + "cost_usd": 931.98, + "availability": 0.989306, + "gen_feat_1": 486.79, + "gen_feat_2": 0.511194, + "gen_feat_3": 509.55 + } + }, + { + "id": "t_accommodation_booking_gen_6", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_5", + "name": "ABS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 441.94, + "cost_usd": 938.72, + "availability": 1.0, + "gen_feat_1": 500.85, + "gen_feat_2": 0.494949, + "gen_feat_3": 494.14 + } + }, + { + "id": "t_accommodation_booking_gen_7", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_a", + "name": "ABS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 438.16, + "cost_usd": 938.79, + "availability": 1.0, + "gen_feat_1": 485.27, + "gen_feat_2": 0.498913, + "gen_feat_3": 487.12 + } + }, + { + "id": "t_accommodation_booking_gen_8", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_b", + "name": "ABS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 418.07, + "cost_usd": 922.82, + "availability": 1.0, + "gen_feat_1": 497.81, + "gen_feat_2": 0.502515, + "gen_feat_3": 509.16 + } + }, + { + "id": "t_car_rental_booking_gen_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_a", + "name": "CRS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 312.13, + "cost_usd": 261.53, + "availability": 1.0, + "gen_feat_1": 512.64, + "gen_feat_2": 0.496089, + "gen_feat_3": 504.19 + } + }, + { + "id": "t_car_rental_booking_gen_3", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_b", + "name": "CRS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 313.91, + "cost_usd": 257.49, + "availability": 0.98681, + "gen_feat_1": 512.87, + "gen_feat_2": 0.505241, + "gen_feat_3": 507.29 + } + }, + { + "id": "t_car_rental_booking_gen_4", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_a", + "name": "CRS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 302.5, + "cost_usd": 253.26, + "availability": 0.988174, + "gen_feat_1": 486.1, + "gen_feat_2": 0.485054, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_car_rental_booking_gen_5", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_b", + "name": "CRS.booking (Gen p_int_air_b)", + "features": { + "latency_ms": 318.31, + "cost_usd": 266.75, + "availability": 0.978032, + "gen_feat_1": 497.95, + "gen_feat_2": 0.49628, + "gen_feat_3": 508.32 + } + }, + { + "id": "t_car_rental_booking_gen_6", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_a", + "name": "CRS.booking (Gen p_ins_a)", + "features": { + "latency_ms": 315.37, + "cost_usd": 257.45, + "availability": 0.991843, + "gen_feat_1": 510.59, + "gen_feat_2": 0.501464, + "gen_feat_3": 495.6 + } + }, + { + "id": "t_car_rental_booking_gen_7", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_b", + "name": "CRS.booking (Gen p_ins_b)", + "features": { + "latency_ms": 311.72, + "cost_usd": 255.51, + "availability": 0.984838, + "gen_feat_1": 498.99, + "gen_feat_2": 0.505672, + "gen_feat_3": 506.54 + } + }, + { + "id": "t_car_rental_booking_gen_8", + "task_id": "t_car_rental_booking", + "provider_id": "p_hotel_a", + "name": "CRS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 306.59, + "cost_usd": 258.27, + "availability": 1.0, + "gen_feat_1": 512.19, + "gen_feat_2": 0.506375, + "gen_feat_3": 513.91 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_parallel", + "kind": "AND", + "children": [ + { + "id": "n_as", + "kind": "TASK", + "task_id": "t_attractions_search" + }, + { + "id": "n_booking_flow", + "kind": "SEQ", + "children": [ + { + "id": "n_flight_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.6, + "child": { + "id": "n_dfb", + "kind": "TASK", + "task_id": "t_flight_booking_domestic" + } + }, + { + "p": 0.4, + "child": { + "id": "n_intl_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_ifb", + "kind": "TASK", + "task_id": "t_flight_booking_international" + }, + { + "id": "n_ti", + "kind": "TASK", + "task_id": "t_travel_insurance" + } + ] + } + } + ] + }, + { + "id": "n_ab", + "kind": "TASK", + "task_id": "t_accommodation_booking" + } + ] + } + ] + }, + { + "id": "n_car_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.3, + "child": { + "id": "n_cr", + "kind": "TASK", + "task_id": "t_car_rental_booking" + } + }, + { + "p": 0.7, + "child": { + "id": "n_no_car", + "kind": "ELEMENT", + "description": "Skip car rental (represents the near(...) branch)" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MANY", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1301.98, + "hard": false + }, + { + "id": "gen_c_local_t_accommodation_booking_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_accommodation_booking" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 927.58, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_attractions_search" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_car_rental_booking" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_mono_one_hard.json b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_mono_one_hard.json new file mode 100644 index 0000000..c4b8e28 --- /dev/null +++ b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_mono_one_hard.json @@ -0,0 +1,1268 @@ +{ + "metadata": { + "id": "benatallah2002-selfserv-travel-solution-cts-itas_mono_one_hard", + "name": "Travel Solution (Benatallah et al. 2002) [mono_one, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from the SELF-SERV running example (CTS and ITAS statecharts). QoS values and branch probabilities are illustrative because the paper does not provide numeric QoS.", + "paper": { + "title": "Declarative Compositionand Peer-to-PeerProvisioning of Dynamic WebServices", + "authors": "B. Benatallah et al.", + "year": 2002, + "doi": "10.5555/876875.878987" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Total price charged to customer", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "availability", + "name": "Probability the service invocation succeeds", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_attractions_a", + "name": "AttractionsSearch Provider A" + }, + { + "id": "p_attractions_b", + "name": "AttractionsSearch Provider B" + }, + { + "id": "p_dom_air_a", + "name": "Domestic Airline A" + }, + { + "id": "p_dom_air_b", + "name": "Domestic Airline B" + }, + { + "id": "p_int_air_a", + "name": "International Airline A" + }, + { + "id": "p_int_air_b", + "name": "International Airline B" + }, + { + "id": "p_ins_a", + "name": "Travel Insurance Co. A" + }, + { + "id": "p_ins_b", + "name": "Travel Insurance Co. B" + }, + { + "id": "p_hotel_a", + "name": "Accommodation Provider A" + }, + { + "id": "p_hotel_b", + "name": "Accommodation Provider B" + }, + { + "id": "p_car_a", + "name": "Car Rental Provider A" + }, + { + "id": "p_car_b", + "name": "Car Rental Provider B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_attractions_search", + "name": "Attractions Search (ASS.getAttractions)" + }, + { + "id": "t_flight_booking_domestic", + "name": "Domestic Flight Booking (DFBS.booking)" + }, + { + "id": "t_flight_booking_international", + "name": "International Flight Booking (IFBS.booking)" + }, + { + "id": "t_travel_insurance", + "name": "Travel Insurance (TIS.getInsurance)" + }, + { + "id": "t_accommodation_booking", + "name": "Accommodation Booking (ABS.booking)" + }, + { + "id": "t_car_rental_booking", + "name": "Car Rental Booking (CRS.booking)" + } + ], + "candidates": [ + { + "id": "svc_ass_1", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_a", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 180, + "cost_usd": 0, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ass_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 120, + "cost_usd": 5, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_a", + "name": "DFBS.booking", + "features": { + "latency_ms": 650, + "cost_usd": 420, + "availability": 0.985, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_b", + "name": "DFBS.booking", + "features": { + "latency_ms": 520, + "cost_usd": 460, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking", + "features": { + "latency_ms": 780, + "cost_usd": 820, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_b", + "name": "IFBS.booking", + "features": { + "latency_ms": 610, + "cost_usd": 900, + "availability": 0.988, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_1", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 240, + "cost_usd": 55, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_2", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 190, + "cost_usd": 70, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_a", + "name": "ABS.booking", + "features": { + "latency_ms": 430, + "cost_usd": 950, + "availability": 0.992, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_b", + "name": "ABS.booking", + "features": { + "latency_ms": 350, + "cost_usd": 1100, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_a", + "name": "CRS.booking", + "features": { + "latency_ms": 310, + "cost_usd": 260, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_b", + "name": "CRS.booking", + "features": { + "latency_ms": 260, + "cost_usd": 320, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_attractions_search_gen_1", + "task_id": "t_attractions_search", + "provider_id": "p_gen_shared", + "name": "ASS.getAttractions (Gen Shared)", + "features": { + "latency_ms": 180.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.57, + "gen_feat_2": 0.493935, + "gen_feat_3": 485.71 + } + }, + { + "id": "t_flight_booking_domestic_gen_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_shared", + "name": "DFBS.booking (Gen Shared)", + "features": { + "latency_ms": 647.32, + "cost_usd": 411.46, + "availability": 0.979506, + "gen_feat_1": 505.68, + "gen_feat_2": 0.506905, + "gen_feat_3": 510.18 + } + }, + { + "id": "t_flight_booking_international_gen_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_shared", + "name": "IFBS.booking (Gen Shared)", + "features": { + "latency_ms": 759.62, + "cost_usd": 814.07, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.503149, + "gen_feat_3": 501.18 + } + }, + { + "id": "t_travel_insurance_gen_1", + "task_id": "t_travel_insurance", + "provider_id": "p_gen_shared", + "name": "TIS.getInsurance (Gen Shared)", + "features": { + "latency_ms": 234.01, + "cost_usd": 55.73, + "availability": 0.994473, + "gen_feat_1": 505.2, + "gen_feat_2": 0.498515, + "gen_feat_3": 487.21 + } + }, + { + "id": "t_accommodation_booking_gen_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_shared", + "name": "ABS.booking (Gen Shared)", + "features": { + "latency_ms": 423.14, + "cost_usd": 927.58, + "availability": 0.985309, + "gen_feat_1": 494.62, + "gen_feat_2": 0.504056, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_car_rental_booking_gen_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_gen_shared", + "name": "CRS.booking (Gen Shared)", + "features": { + "latency_ms": 303.36, + "cost_usd": 252.45, + "availability": 0.962251, + "gen_feat_1": 502.73, + "gen_feat_2": 0.492905, + "gen_feat_3": 511.21 + } + }, + { + "id": "t_attractions_search_gen_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions (Gen p_attractions_b)", + "features": { + "latency_ms": 183.9, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.11, + "gen_feat_2": 0.507033, + "gen_feat_3": 506.35 + } + }, + { + "id": "t_attractions_search_gen_3", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_a", + "name": "ASS.getAttractions (Gen p_dom_air_a)", + "features": { + "latency_ms": 184.86, + "cost_usd": 0.0, + "availability": 0.973261, + "gen_feat_1": 512.0, + "gen_feat_2": 0.499623, + "gen_feat_3": 508.68 + } + }, + { + "id": "t_attractions_search_gen_4", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_b", + "name": "ASS.getAttractions (Gen p_dom_air_b)", + "features": { + "latency_ms": 177.98, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.492691, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_attractions_search_gen_5", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_a", + "name": "ASS.getAttractions (Gen p_int_air_a)", + "features": { + "latency_ms": 180.31, + "cost_usd": 0.0, + "availability": 0.975329, + "gen_feat_1": 511.15, + "gen_feat_2": 0.485867, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_attractions_search_gen_6", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_b", + "name": "ASS.getAttractions (Gen p_int_air_b)", + "features": { + "latency_ms": 178.35, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 491.67, + "gen_feat_2": 0.511467, + "gen_feat_3": 505.28 + } + }, + { + "id": "t_attractions_search_gen_7", + "task_id": "t_attractions_search", + "provider_id": "p_ins_a", + "name": "ASS.getAttractions (Gen p_ins_a)", + "features": { + "latency_ms": 183.13, + "cost_usd": 0.0, + "availability": 0.982652, + "gen_feat_1": 486.89, + "gen_feat_2": 0.493076, + "gen_feat_3": 489.66 + } + }, + { + "id": "t_attractions_search_gen_8", + "task_id": "t_attractions_search", + "provider_id": "p_ins_b", + "name": "ASS.getAttractions (Gen p_ins_b)", + "features": { + "latency_ms": 176.67, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.91, + "gen_feat_2": 0.510797, + "gen_feat_3": 494.78 + } + }, + { + "id": "t_flight_booking_domestic_gen_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_a", + "name": "DFBS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 631.95, + "cost_usd": 420.96, + "availability": 0.993293, + "gen_feat_1": 509.36, + "gen_feat_2": 0.48832, + "gen_feat_3": 493.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_3", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_b", + "name": "DFBS.booking (Gen p_hotel_b)", + "features": { + "latency_ms": 657.0, + "cost_usd": 410.51, + "availability": 1.0, + "gen_feat_1": 512.88, + "gen_feat_2": 0.494914, + "gen_feat_3": 493.16 + } + }, + { + "id": "t_flight_booking_domestic_gen_4", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_a", + "name": "DFBS.booking (Gen p_car_a)", + "features": { + "latency_ms": 662.74, + "cost_usd": 432.29, + "availability": 0.955965, + "gen_feat_1": 500.97, + "gen_feat_2": 0.486536, + "gen_feat_3": 491.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_5", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_b", + "name": "DFBS.booking (Gen p_car_b)", + "features": { + "latency_ms": 660.26, + "cost_usd": 422.73, + "availability": 1.0, + "gen_feat_1": 511.72, + "gen_feat_2": 0.496489, + "gen_feat_3": 514.27 + } + }, + { + "id": "t_flight_booking_domestic_gen_6", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_1", + "name": "DFBS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 638.86, + "cost_usd": 413.02, + "availability": 0.985773, + "gen_feat_1": 498.15, + "gen_feat_2": 0.488561, + "gen_feat_3": 503.45 + } + }, + { + "id": "t_flight_booking_domestic_gen_7", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_2", + "name": "DFBS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 641.08, + "cost_usd": 429.65, + "availability": 0.978204, + "gen_feat_1": 506.04, + "gen_feat_2": 0.496573, + "gen_feat_3": 510.36 + } + }, + { + "id": "t_flight_booking_domestic_gen_8", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_3", + "name": "DFBS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 664.71, + "cost_usd": 414.68, + "availability": 0.966781, + "gen_feat_1": 489.74, + "gen_feat_2": 0.487447, + "gen_feat_3": 486.76 + } + }, + { + "id": "t_flight_booking_international_gen_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_4", + "name": "IFBS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 802.29, + "cost_usd": 805.78, + "availability": 0.988419, + "gen_feat_1": 509.12, + "gen_feat_2": 0.493932, + "gen_feat_3": 494.56 + } + }, + { + "id": "t_flight_booking_international_gen_3", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_5", + "name": "IFBS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 785.65, + "cost_usd": 832.67, + "availability": 1.0, + "gen_feat_1": 498.69, + "gen_feat_2": 0.506699, + "gen_feat_3": 486.23 + } + }, + { + "id": "t_flight_booking_international_gen_4", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_a", + "name": "IFBS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 795.93, + "cost_usd": 844.09, + "availability": 0.963688, + "gen_feat_1": 492.63, + "gen_feat_2": 0.50024, + "gen_feat_3": 503.14 + } + }, + { + "id": "t_flight_booking_international_gen_5", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_b", + "name": "IFBS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 763.55, + "cost_usd": 806.59, + "availability": 0.973216, + "gen_feat_1": 490.91, + "gen_feat_2": 0.504181, + "gen_feat_3": 493.32 + } + }, + { + "id": "t_flight_booking_international_gen_6", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_a", + "name": "IFBS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 775.31, + "cost_usd": 813.89, + "availability": 1.0, + "gen_feat_1": 514.34, + "gen_feat_2": 0.490809, + "gen_feat_3": 502.88 + } + }, + { + "id": "t_flight_booking_international_gen_7", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_b", + "name": "IFBS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 774.09, + "cost_usd": 796.86, + "availability": 1.0, + "gen_feat_1": 509.97, + "gen_feat_2": 0.50639, + "gen_feat_3": 488.65 + } + }, + { + "id": "t_flight_booking_international_gen_8", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 802.89, + "cost_usd": 832.54, + "availability": 0.995867, + "gen_feat_1": 500.61, + "gen_feat_2": 0.492753, + "gen_feat_3": 489.35 + } + }, + { + "id": "t_travel_insurance_gen_2", + "task_id": "t_travel_insurance", + "provider_id": "p_int_air_b", + "name": "TIS.getInsurance (Gen p_int_air_b)", + "features": { + "latency_ms": 239.89, + "cost_usd": 54.54, + "availability": 0.978354, + "gen_feat_1": 504.59, + "gen_feat_2": 0.502031, + "gen_feat_3": 500.67 + } + }, + { + "id": "t_travel_insurance_gen_3", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance (Gen p_ins_a)", + "features": { + "latency_ms": 235.94, + "cost_usd": 55.24, + "availability": 1.0, + "gen_feat_1": 510.78, + "gen_feat_2": 0.49515, + "gen_feat_3": 514.3 + } + }, + { + "id": "t_travel_insurance_gen_4", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance (Gen p_ins_b)", + "features": { + "latency_ms": 239.19, + "cost_usd": 54.65, + "availability": 0.97242, + "gen_feat_1": 493.99, + "gen_feat_2": 0.507973, + "gen_feat_3": 491.39 + } + }, + { + "id": "t_travel_insurance_gen_5", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_a", + "name": "TIS.getInsurance (Gen p_hotel_a)", + "features": { + "latency_ms": 237.46, + "cost_usd": 55.4, + "availability": 1.0, + "gen_feat_1": 502.98, + "gen_feat_2": 0.490074, + "gen_feat_3": 504.05 + } + }, + { + "id": "t_travel_insurance_gen_6", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_b", + "name": "TIS.getInsurance (Gen p_hotel_b)", + "features": { + "latency_ms": 246.8, + "cost_usd": 55.95, + "availability": 0.997177, + "gen_feat_1": 498.91, + "gen_feat_2": 0.494214, + "gen_feat_3": 502.98 + } + }, + { + "id": "t_travel_insurance_gen_7", + "task_id": "t_travel_insurance", + "provider_id": "p_car_a", + "name": "TIS.getInsurance (Gen p_car_a)", + "features": { + "latency_ms": 246.54, + "cost_usd": 54.9, + "availability": 0.99944, + "gen_feat_1": 492.97, + "gen_feat_2": 0.512985, + "gen_feat_3": 497.1 + } + }, + { + "id": "t_travel_insurance_gen_8", + "task_id": "t_travel_insurance", + "provider_id": "p_car_b", + "name": "TIS.getInsurance (Gen p_car_b)", + "features": { + "latency_ms": 245.14, + "cost_usd": 53.91, + "availability": 1.0, + "gen_feat_1": 507.6, + "gen_feat_2": 0.491973, + "gen_feat_3": 489.42 + } + }, + { + "id": "t_accommodation_booking_gen_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_1", + "name": "ABS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 417.7, + "cost_usd": 957.65, + "availability": 1.0, + "gen_feat_1": 491.17, + "gen_feat_2": 0.487995, + "gen_feat_3": 496.04 + } + }, + { + "id": "t_accommodation_booking_gen_3", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_2", + "name": "ABS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 435.3, + "cost_usd": 943.55, + "availability": 0.98734, + "gen_feat_1": 490.66, + "gen_feat_2": 0.512804, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_accommodation_booking_gen_4", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_3", + "name": "ABS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 424.85, + "cost_usd": 946.36, + "availability": 0.983088, + "gen_feat_1": 490.8, + "gen_feat_2": 0.498715, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_accommodation_booking_gen_5", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_4", + "name": "ABS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 437.83, + "cost_usd": 931.98, + "availability": 0.989306, + "gen_feat_1": 486.79, + "gen_feat_2": 0.511194, + "gen_feat_3": 509.55 + } + }, + { + "id": "t_accommodation_booking_gen_6", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_5", + "name": "ABS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 441.94, + "cost_usd": 938.72, + "availability": 1.0, + "gen_feat_1": 500.85, + "gen_feat_2": 0.494949, + "gen_feat_3": 494.14 + } + }, + { + "id": "t_accommodation_booking_gen_7", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_a", + "name": "ABS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 438.16, + "cost_usd": 938.79, + "availability": 1.0, + "gen_feat_1": 485.27, + "gen_feat_2": 0.498913, + "gen_feat_3": 487.12 + } + }, + { + "id": "t_accommodation_booking_gen_8", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_b", + "name": "ABS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 418.07, + "cost_usd": 922.82, + "availability": 1.0, + "gen_feat_1": 497.81, + "gen_feat_2": 0.502515, + "gen_feat_3": 509.16 + } + }, + { + "id": "t_car_rental_booking_gen_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_a", + "name": "CRS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 312.13, + "cost_usd": 261.53, + "availability": 1.0, + "gen_feat_1": 512.64, + "gen_feat_2": 0.496089, + "gen_feat_3": 504.19 + } + }, + { + "id": "t_car_rental_booking_gen_3", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_b", + "name": "CRS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 313.91, + "cost_usd": 257.49, + "availability": 0.98681, + "gen_feat_1": 512.87, + "gen_feat_2": 0.505241, + "gen_feat_3": 507.29 + } + }, + { + "id": "t_car_rental_booking_gen_4", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_a", + "name": "CRS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 302.5, + "cost_usd": 253.26, + "availability": 0.988174, + "gen_feat_1": 486.1, + "gen_feat_2": 0.485054, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_car_rental_booking_gen_5", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_b", + "name": "CRS.booking (Gen p_int_air_b)", + "features": { + "latency_ms": 318.31, + "cost_usd": 266.75, + "availability": 0.978032, + "gen_feat_1": 497.95, + "gen_feat_2": 0.49628, + "gen_feat_3": 508.32 + } + }, + { + "id": "t_car_rental_booking_gen_6", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_a", + "name": "CRS.booking (Gen p_ins_a)", + "features": { + "latency_ms": 315.37, + "cost_usd": 257.45, + "availability": 0.991843, + "gen_feat_1": 510.59, + "gen_feat_2": 0.501464, + "gen_feat_3": 495.6 + } + }, + { + "id": "t_car_rental_booking_gen_7", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_b", + "name": "CRS.booking (Gen p_ins_b)", + "features": { + "latency_ms": 311.72, + "cost_usd": 255.51, + "availability": 0.984838, + "gen_feat_1": 498.99, + "gen_feat_2": 0.505672, + "gen_feat_3": 506.54 + } + }, + { + "id": "t_car_rental_booking_gen_8", + "task_id": "t_car_rental_booking", + "provider_id": "p_hotel_a", + "name": "CRS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 306.59, + "cost_usd": 258.27, + "availability": 1.0, + "gen_feat_1": 512.19, + "gen_feat_2": 0.506375, + "gen_feat_3": 513.91 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_parallel", + "kind": "AND", + "children": [ + { + "id": "n_as", + "kind": "TASK", + "task_id": "t_attractions_search" + }, + { + "id": "n_booking_flow", + "kind": "SEQ", + "children": [ + { + "id": "n_flight_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.6, + "child": { + "id": "n_dfb", + "kind": "TASK", + "task_id": "t_flight_booking_domestic" + } + }, + { + "p": 0.4, + "child": { + "id": "n_intl_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_ifb", + "kind": "TASK", + "task_id": "t_flight_booking_international" + }, + { + "id": "n_ti", + "kind": "TASK", + "task_id": "t_travel_insurance" + } + ] + } + } + ] + }, + { + "id": "n_ab", + "kind": "TASK", + "task_id": "t_accommodation_booking" + } + ] + } + ] + }, + { + "id": "n_car_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.3, + "child": { + "id": "n_cr", + "kind": "TASK", + "task_id": "t_car_rental_booking" + } + }, + { + "p": 0.7, + "child": { + "id": "n_no_car", + "kind": "ELEMENT", + "description": "Skip car rental (represents the near(...) branch)" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "availability" + ], + "weights": { + "availability": 1.0 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1301.98, + "hard": true + }, + { + "id": "gen_c_local_t_accommodation_booking_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_accommodation_booking" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 927.58, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_attractions_search" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_car_rental_booking" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_mono_one_soft.json b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_mono_one_soft.json new file mode 100644 index 0000000..c8371af --- /dev/null +++ b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_mono_one_soft.json @@ -0,0 +1,1268 @@ +{ + "metadata": { + "id": "benatallah2002-selfserv-travel-solution-cts-itas_mono_one_soft", + "name": "Travel Solution (Benatallah et al. 2002) [mono_one, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from the SELF-SERV running example (CTS and ITAS statecharts). QoS values and branch probabilities are illustrative because the paper does not provide numeric QoS.", + "paper": { + "title": "Declarative Compositionand Peer-to-PeerProvisioning of Dynamic WebServices", + "authors": "B. Benatallah et al.", + "year": 2002, + "doi": "10.5555/876875.878987" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Total price charged to customer", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "availability", + "name": "Probability the service invocation succeeds", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_attractions_a", + "name": "AttractionsSearch Provider A" + }, + { + "id": "p_attractions_b", + "name": "AttractionsSearch Provider B" + }, + { + "id": "p_dom_air_a", + "name": "Domestic Airline A" + }, + { + "id": "p_dom_air_b", + "name": "Domestic Airline B" + }, + { + "id": "p_int_air_a", + "name": "International Airline A" + }, + { + "id": "p_int_air_b", + "name": "International Airline B" + }, + { + "id": "p_ins_a", + "name": "Travel Insurance Co. A" + }, + { + "id": "p_ins_b", + "name": "Travel Insurance Co. B" + }, + { + "id": "p_hotel_a", + "name": "Accommodation Provider A" + }, + { + "id": "p_hotel_b", + "name": "Accommodation Provider B" + }, + { + "id": "p_car_a", + "name": "Car Rental Provider A" + }, + { + "id": "p_car_b", + "name": "Car Rental Provider B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_attractions_search", + "name": "Attractions Search (ASS.getAttractions)" + }, + { + "id": "t_flight_booking_domestic", + "name": "Domestic Flight Booking (DFBS.booking)" + }, + { + "id": "t_flight_booking_international", + "name": "International Flight Booking (IFBS.booking)" + }, + { + "id": "t_travel_insurance", + "name": "Travel Insurance (TIS.getInsurance)" + }, + { + "id": "t_accommodation_booking", + "name": "Accommodation Booking (ABS.booking)" + }, + { + "id": "t_car_rental_booking", + "name": "Car Rental Booking (CRS.booking)" + } + ], + "candidates": [ + { + "id": "svc_ass_1", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_a", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 180, + "cost_usd": 0, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ass_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 120, + "cost_usd": 5, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_a", + "name": "DFBS.booking", + "features": { + "latency_ms": 650, + "cost_usd": 420, + "availability": 0.985, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_b", + "name": "DFBS.booking", + "features": { + "latency_ms": 520, + "cost_usd": 460, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking", + "features": { + "latency_ms": 780, + "cost_usd": 820, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_b", + "name": "IFBS.booking", + "features": { + "latency_ms": 610, + "cost_usd": 900, + "availability": 0.988, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_1", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 240, + "cost_usd": 55, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_2", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 190, + "cost_usd": 70, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_a", + "name": "ABS.booking", + "features": { + "latency_ms": 430, + "cost_usd": 950, + "availability": 0.992, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_b", + "name": "ABS.booking", + "features": { + "latency_ms": 350, + "cost_usd": 1100, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_a", + "name": "CRS.booking", + "features": { + "latency_ms": 310, + "cost_usd": 260, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_b", + "name": "CRS.booking", + "features": { + "latency_ms": 260, + "cost_usd": 320, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_attractions_search_gen_1", + "task_id": "t_attractions_search", + "provider_id": "p_gen_shared", + "name": "ASS.getAttractions (Gen Shared)", + "features": { + "latency_ms": 180.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.57, + "gen_feat_2": 0.493935, + "gen_feat_3": 485.71 + } + }, + { + "id": "t_flight_booking_domestic_gen_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_shared", + "name": "DFBS.booking (Gen Shared)", + "features": { + "latency_ms": 647.32, + "cost_usd": 411.46, + "availability": 0.979506, + "gen_feat_1": 505.68, + "gen_feat_2": 0.506905, + "gen_feat_3": 510.18 + } + }, + { + "id": "t_flight_booking_international_gen_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_shared", + "name": "IFBS.booking (Gen Shared)", + "features": { + "latency_ms": 759.62, + "cost_usd": 814.07, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.503149, + "gen_feat_3": 501.18 + } + }, + { + "id": "t_travel_insurance_gen_1", + "task_id": "t_travel_insurance", + "provider_id": "p_gen_shared", + "name": "TIS.getInsurance (Gen Shared)", + "features": { + "latency_ms": 234.01, + "cost_usd": 55.73, + "availability": 0.994473, + "gen_feat_1": 505.2, + "gen_feat_2": 0.498515, + "gen_feat_3": 487.21 + } + }, + { + "id": "t_accommodation_booking_gen_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_shared", + "name": "ABS.booking (Gen Shared)", + "features": { + "latency_ms": 423.14, + "cost_usd": 927.58, + "availability": 0.985309, + "gen_feat_1": 494.62, + "gen_feat_2": 0.504056, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_car_rental_booking_gen_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_gen_shared", + "name": "CRS.booking (Gen Shared)", + "features": { + "latency_ms": 303.36, + "cost_usd": 252.45, + "availability": 0.962251, + "gen_feat_1": 502.73, + "gen_feat_2": 0.492905, + "gen_feat_3": 511.21 + } + }, + { + "id": "t_attractions_search_gen_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions (Gen p_attractions_b)", + "features": { + "latency_ms": 183.9, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.11, + "gen_feat_2": 0.507033, + "gen_feat_3": 506.35 + } + }, + { + "id": "t_attractions_search_gen_3", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_a", + "name": "ASS.getAttractions (Gen p_dom_air_a)", + "features": { + "latency_ms": 184.86, + "cost_usd": 0.0, + "availability": 0.973261, + "gen_feat_1": 512.0, + "gen_feat_2": 0.499623, + "gen_feat_3": 508.68 + } + }, + { + "id": "t_attractions_search_gen_4", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_b", + "name": "ASS.getAttractions (Gen p_dom_air_b)", + "features": { + "latency_ms": 177.98, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.492691, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_attractions_search_gen_5", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_a", + "name": "ASS.getAttractions (Gen p_int_air_a)", + "features": { + "latency_ms": 180.31, + "cost_usd": 0.0, + "availability": 0.975329, + "gen_feat_1": 511.15, + "gen_feat_2": 0.485867, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_attractions_search_gen_6", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_b", + "name": "ASS.getAttractions (Gen p_int_air_b)", + "features": { + "latency_ms": 178.35, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 491.67, + "gen_feat_2": 0.511467, + "gen_feat_3": 505.28 + } + }, + { + "id": "t_attractions_search_gen_7", + "task_id": "t_attractions_search", + "provider_id": "p_ins_a", + "name": "ASS.getAttractions (Gen p_ins_a)", + "features": { + "latency_ms": 183.13, + "cost_usd": 0.0, + "availability": 0.982652, + "gen_feat_1": 486.89, + "gen_feat_2": 0.493076, + "gen_feat_3": 489.66 + } + }, + { + "id": "t_attractions_search_gen_8", + "task_id": "t_attractions_search", + "provider_id": "p_ins_b", + "name": "ASS.getAttractions (Gen p_ins_b)", + "features": { + "latency_ms": 176.67, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.91, + "gen_feat_2": 0.510797, + "gen_feat_3": 494.78 + } + }, + { + "id": "t_flight_booking_domestic_gen_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_a", + "name": "DFBS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 631.95, + "cost_usd": 420.96, + "availability": 0.993293, + "gen_feat_1": 509.36, + "gen_feat_2": 0.48832, + "gen_feat_3": 493.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_3", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_b", + "name": "DFBS.booking (Gen p_hotel_b)", + "features": { + "latency_ms": 657.0, + "cost_usd": 410.51, + "availability": 1.0, + "gen_feat_1": 512.88, + "gen_feat_2": 0.494914, + "gen_feat_3": 493.16 + } + }, + { + "id": "t_flight_booking_domestic_gen_4", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_a", + "name": "DFBS.booking (Gen p_car_a)", + "features": { + "latency_ms": 662.74, + "cost_usd": 432.29, + "availability": 0.955965, + "gen_feat_1": 500.97, + "gen_feat_2": 0.486536, + "gen_feat_3": 491.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_5", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_b", + "name": "DFBS.booking (Gen p_car_b)", + "features": { + "latency_ms": 660.26, + "cost_usd": 422.73, + "availability": 1.0, + "gen_feat_1": 511.72, + "gen_feat_2": 0.496489, + "gen_feat_3": 514.27 + } + }, + { + "id": "t_flight_booking_domestic_gen_6", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_1", + "name": "DFBS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 638.86, + "cost_usd": 413.02, + "availability": 0.985773, + "gen_feat_1": 498.15, + "gen_feat_2": 0.488561, + "gen_feat_3": 503.45 + } + }, + { + "id": "t_flight_booking_domestic_gen_7", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_2", + "name": "DFBS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 641.08, + "cost_usd": 429.65, + "availability": 0.978204, + "gen_feat_1": 506.04, + "gen_feat_2": 0.496573, + "gen_feat_3": 510.36 + } + }, + { + "id": "t_flight_booking_domestic_gen_8", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_3", + "name": "DFBS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 664.71, + "cost_usd": 414.68, + "availability": 0.966781, + "gen_feat_1": 489.74, + "gen_feat_2": 0.487447, + "gen_feat_3": 486.76 + } + }, + { + "id": "t_flight_booking_international_gen_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_4", + "name": "IFBS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 802.29, + "cost_usd": 805.78, + "availability": 0.988419, + "gen_feat_1": 509.12, + "gen_feat_2": 0.493932, + "gen_feat_3": 494.56 + } + }, + { + "id": "t_flight_booking_international_gen_3", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_5", + "name": "IFBS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 785.65, + "cost_usd": 832.67, + "availability": 1.0, + "gen_feat_1": 498.69, + "gen_feat_2": 0.506699, + "gen_feat_3": 486.23 + } + }, + { + "id": "t_flight_booking_international_gen_4", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_a", + "name": "IFBS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 795.93, + "cost_usd": 844.09, + "availability": 0.963688, + "gen_feat_1": 492.63, + "gen_feat_2": 0.50024, + "gen_feat_3": 503.14 + } + }, + { + "id": "t_flight_booking_international_gen_5", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_b", + "name": "IFBS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 763.55, + "cost_usd": 806.59, + "availability": 0.973216, + "gen_feat_1": 490.91, + "gen_feat_2": 0.504181, + "gen_feat_3": 493.32 + } + }, + { + "id": "t_flight_booking_international_gen_6", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_a", + "name": "IFBS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 775.31, + "cost_usd": 813.89, + "availability": 1.0, + "gen_feat_1": 514.34, + "gen_feat_2": 0.490809, + "gen_feat_3": 502.88 + } + }, + { + "id": "t_flight_booking_international_gen_7", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_b", + "name": "IFBS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 774.09, + "cost_usd": 796.86, + "availability": 1.0, + "gen_feat_1": 509.97, + "gen_feat_2": 0.50639, + "gen_feat_3": 488.65 + } + }, + { + "id": "t_flight_booking_international_gen_8", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 802.89, + "cost_usd": 832.54, + "availability": 0.995867, + "gen_feat_1": 500.61, + "gen_feat_2": 0.492753, + "gen_feat_3": 489.35 + } + }, + { + "id": "t_travel_insurance_gen_2", + "task_id": "t_travel_insurance", + "provider_id": "p_int_air_b", + "name": "TIS.getInsurance (Gen p_int_air_b)", + "features": { + "latency_ms": 239.89, + "cost_usd": 54.54, + "availability": 0.978354, + "gen_feat_1": 504.59, + "gen_feat_2": 0.502031, + "gen_feat_3": 500.67 + } + }, + { + "id": "t_travel_insurance_gen_3", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance (Gen p_ins_a)", + "features": { + "latency_ms": 235.94, + "cost_usd": 55.24, + "availability": 1.0, + "gen_feat_1": 510.78, + "gen_feat_2": 0.49515, + "gen_feat_3": 514.3 + } + }, + { + "id": "t_travel_insurance_gen_4", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance (Gen p_ins_b)", + "features": { + "latency_ms": 239.19, + "cost_usd": 54.65, + "availability": 0.97242, + "gen_feat_1": 493.99, + "gen_feat_2": 0.507973, + "gen_feat_3": 491.39 + } + }, + { + "id": "t_travel_insurance_gen_5", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_a", + "name": "TIS.getInsurance (Gen p_hotel_a)", + "features": { + "latency_ms": 237.46, + "cost_usd": 55.4, + "availability": 1.0, + "gen_feat_1": 502.98, + "gen_feat_2": 0.490074, + "gen_feat_3": 504.05 + } + }, + { + "id": "t_travel_insurance_gen_6", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_b", + "name": "TIS.getInsurance (Gen p_hotel_b)", + "features": { + "latency_ms": 246.8, + "cost_usd": 55.95, + "availability": 0.997177, + "gen_feat_1": 498.91, + "gen_feat_2": 0.494214, + "gen_feat_3": 502.98 + } + }, + { + "id": "t_travel_insurance_gen_7", + "task_id": "t_travel_insurance", + "provider_id": "p_car_a", + "name": "TIS.getInsurance (Gen p_car_a)", + "features": { + "latency_ms": 246.54, + "cost_usd": 54.9, + "availability": 0.99944, + "gen_feat_1": 492.97, + "gen_feat_2": 0.512985, + "gen_feat_3": 497.1 + } + }, + { + "id": "t_travel_insurance_gen_8", + "task_id": "t_travel_insurance", + "provider_id": "p_car_b", + "name": "TIS.getInsurance (Gen p_car_b)", + "features": { + "latency_ms": 245.14, + "cost_usd": 53.91, + "availability": 1.0, + "gen_feat_1": 507.6, + "gen_feat_2": 0.491973, + "gen_feat_3": 489.42 + } + }, + { + "id": "t_accommodation_booking_gen_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_1", + "name": "ABS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 417.7, + "cost_usd": 957.65, + "availability": 1.0, + "gen_feat_1": 491.17, + "gen_feat_2": 0.487995, + "gen_feat_3": 496.04 + } + }, + { + "id": "t_accommodation_booking_gen_3", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_2", + "name": "ABS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 435.3, + "cost_usd": 943.55, + "availability": 0.98734, + "gen_feat_1": 490.66, + "gen_feat_2": 0.512804, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_accommodation_booking_gen_4", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_3", + "name": "ABS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 424.85, + "cost_usd": 946.36, + "availability": 0.983088, + "gen_feat_1": 490.8, + "gen_feat_2": 0.498715, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_accommodation_booking_gen_5", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_4", + "name": "ABS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 437.83, + "cost_usd": 931.98, + "availability": 0.989306, + "gen_feat_1": 486.79, + "gen_feat_2": 0.511194, + "gen_feat_3": 509.55 + } + }, + { + "id": "t_accommodation_booking_gen_6", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_5", + "name": "ABS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 441.94, + "cost_usd": 938.72, + "availability": 1.0, + "gen_feat_1": 500.85, + "gen_feat_2": 0.494949, + "gen_feat_3": 494.14 + } + }, + { + "id": "t_accommodation_booking_gen_7", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_a", + "name": "ABS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 438.16, + "cost_usd": 938.79, + "availability": 1.0, + "gen_feat_1": 485.27, + "gen_feat_2": 0.498913, + "gen_feat_3": 487.12 + } + }, + { + "id": "t_accommodation_booking_gen_8", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_b", + "name": "ABS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 418.07, + "cost_usd": 922.82, + "availability": 1.0, + "gen_feat_1": 497.81, + "gen_feat_2": 0.502515, + "gen_feat_3": 509.16 + } + }, + { + "id": "t_car_rental_booking_gen_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_a", + "name": "CRS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 312.13, + "cost_usd": 261.53, + "availability": 1.0, + "gen_feat_1": 512.64, + "gen_feat_2": 0.496089, + "gen_feat_3": 504.19 + } + }, + { + "id": "t_car_rental_booking_gen_3", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_b", + "name": "CRS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 313.91, + "cost_usd": 257.49, + "availability": 0.98681, + "gen_feat_1": 512.87, + "gen_feat_2": 0.505241, + "gen_feat_3": 507.29 + } + }, + { + "id": "t_car_rental_booking_gen_4", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_a", + "name": "CRS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 302.5, + "cost_usd": 253.26, + "availability": 0.988174, + "gen_feat_1": 486.1, + "gen_feat_2": 0.485054, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_car_rental_booking_gen_5", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_b", + "name": "CRS.booking (Gen p_int_air_b)", + "features": { + "latency_ms": 318.31, + "cost_usd": 266.75, + "availability": 0.978032, + "gen_feat_1": 497.95, + "gen_feat_2": 0.49628, + "gen_feat_3": 508.32 + } + }, + { + "id": "t_car_rental_booking_gen_6", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_a", + "name": "CRS.booking (Gen p_ins_a)", + "features": { + "latency_ms": 315.37, + "cost_usd": 257.45, + "availability": 0.991843, + "gen_feat_1": 510.59, + "gen_feat_2": 0.501464, + "gen_feat_3": 495.6 + } + }, + { + "id": "t_car_rental_booking_gen_7", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_b", + "name": "CRS.booking (Gen p_ins_b)", + "features": { + "latency_ms": 311.72, + "cost_usd": 255.51, + "availability": 0.984838, + "gen_feat_1": 498.99, + "gen_feat_2": 0.505672, + "gen_feat_3": 506.54 + } + }, + { + "id": "t_car_rental_booking_gen_8", + "task_id": "t_car_rental_booking", + "provider_id": "p_hotel_a", + "name": "CRS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 306.59, + "cost_usd": 258.27, + "availability": 1.0, + "gen_feat_1": 512.19, + "gen_feat_2": 0.506375, + "gen_feat_3": 513.91 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_parallel", + "kind": "AND", + "children": [ + { + "id": "n_as", + "kind": "TASK", + "task_id": "t_attractions_search" + }, + { + "id": "n_booking_flow", + "kind": "SEQ", + "children": [ + { + "id": "n_flight_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.6, + "child": { + "id": "n_dfb", + "kind": "TASK", + "task_id": "t_flight_booking_domestic" + } + }, + { + "p": 0.4, + "child": { + "id": "n_intl_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_ifb", + "kind": "TASK", + "task_id": "t_flight_booking_international" + }, + { + "id": "n_ti", + "kind": "TASK", + "task_id": "t_travel_insurance" + } + ] + } + } + ] + }, + { + "id": "n_ab", + "kind": "TASK", + "task_id": "t_accommodation_booking" + } + ] + } + ] + }, + { + "id": "n_car_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.3, + "child": { + "id": "n_cr", + "kind": "TASK", + "task_id": "t_car_rental_booking" + } + }, + { + "p": 0.7, + "child": { + "id": "n_no_car", + "kind": "ELEMENT", + "description": "Skip car rental (represents the near(...) branch)" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "availability" + ], + "weights": { + "availability": 1.0 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1301.98, + "hard": false + }, + { + "id": "gen_c_local_t_accommodation_booking_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_accommodation_booking" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 927.58, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_attractions_search" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_car_rental_booking" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_mono_utility_hard.json b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_mono_utility_hard.json new file mode 100644 index 0000000..80477a7 --- /dev/null +++ b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_mono_utility_hard.json @@ -0,0 +1,1278 @@ +{ + "metadata": { + "id": "benatallah2002-selfserv-travel-solution-cts-itas_mono_utility_hard", + "name": "Travel Solution (Benatallah et al. 2002) [mono_utility, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from the SELF-SERV running example (CTS and ITAS statecharts). QoS values and branch probabilities are illustrative because the paper does not provide numeric QoS.", + "paper": { + "title": "Declarative Compositionand Peer-to-PeerProvisioning of Dynamic WebServices", + "authors": "B. Benatallah et al.", + "year": 2002, + "doi": "10.5555/876875.878987" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Total price charged to customer", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "availability", + "name": "Probability the service invocation succeeds", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_attractions_a", + "name": "AttractionsSearch Provider A" + }, + { + "id": "p_attractions_b", + "name": "AttractionsSearch Provider B" + }, + { + "id": "p_dom_air_a", + "name": "Domestic Airline A" + }, + { + "id": "p_dom_air_b", + "name": "Domestic Airline B" + }, + { + "id": "p_int_air_a", + "name": "International Airline A" + }, + { + "id": "p_int_air_b", + "name": "International Airline B" + }, + { + "id": "p_ins_a", + "name": "Travel Insurance Co. A" + }, + { + "id": "p_ins_b", + "name": "Travel Insurance Co. B" + }, + { + "id": "p_hotel_a", + "name": "Accommodation Provider A" + }, + { + "id": "p_hotel_b", + "name": "Accommodation Provider B" + }, + { + "id": "p_car_a", + "name": "Car Rental Provider A" + }, + { + "id": "p_car_b", + "name": "Car Rental Provider B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_attractions_search", + "name": "Attractions Search (ASS.getAttractions)" + }, + { + "id": "t_flight_booking_domestic", + "name": "Domestic Flight Booking (DFBS.booking)" + }, + { + "id": "t_flight_booking_international", + "name": "International Flight Booking (IFBS.booking)" + }, + { + "id": "t_travel_insurance", + "name": "Travel Insurance (TIS.getInsurance)" + }, + { + "id": "t_accommodation_booking", + "name": "Accommodation Booking (ABS.booking)" + }, + { + "id": "t_car_rental_booking", + "name": "Car Rental Booking (CRS.booking)" + } + ], + "candidates": [ + { + "id": "svc_ass_1", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_a", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 180, + "cost_usd": 0, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ass_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 120, + "cost_usd": 5, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_a", + "name": "DFBS.booking", + "features": { + "latency_ms": 650, + "cost_usd": 420, + "availability": 0.985, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_b", + "name": "DFBS.booking", + "features": { + "latency_ms": 520, + "cost_usd": 460, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking", + "features": { + "latency_ms": 780, + "cost_usd": 820, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_b", + "name": "IFBS.booking", + "features": { + "latency_ms": 610, + "cost_usd": 900, + "availability": 0.988, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_1", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 240, + "cost_usd": 55, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_2", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 190, + "cost_usd": 70, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_a", + "name": "ABS.booking", + "features": { + "latency_ms": 430, + "cost_usd": 950, + "availability": 0.992, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_b", + "name": "ABS.booking", + "features": { + "latency_ms": 350, + "cost_usd": 1100, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_a", + "name": "CRS.booking", + "features": { + "latency_ms": 310, + "cost_usd": 260, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_b", + "name": "CRS.booking", + "features": { + "latency_ms": 260, + "cost_usd": 320, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_attractions_search_gen_1", + "task_id": "t_attractions_search", + "provider_id": "p_gen_shared", + "name": "ASS.getAttractions (Gen Shared)", + "features": { + "latency_ms": 180.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.57, + "gen_feat_2": 0.493935, + "gen_feat_3": 485.71 + } + }, + { + "id": "t_flight_booking_domestic_gen_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_shared", + "name": "DFBS.booking (Gen Shared)", + "features": { + "latency_ms": 647.32, + "cost_usd": 411.46, + "availability": 0.979506, + "gen_feat_1": 505.68, + "gen_feat_2": 0.506905, + "gen_feat_3": 510.18 + } + }, + { + "id": "t_flight_booking_international_gen_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_shared", + "name": "IFBS.booking (Gen Shared)", + "features": { + "latency_ms": 759.62, + "cost_usd": 814.07, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.503149, + "gen_feat_3": 501.18 + } + }, + { + "id": "t_travel_insurance_gen_1", + "task_id": "t_travel_insurance", + "provider_id": "p_gen_shared", + "name": "TIS.getInsurance (Gen Shared)", + "features": { + "latency_ms": 234.01, + "cost_usd": 55.73, + "availability": 0.994473, + "gen_feat_1": 505.2, + "gen_feat_2": 0.498515, + "gen_feat_3": 487.21 + } + }, + { + "id": "t_accommodation_booking_gen_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_shared", + "name": "ABS.booking (Gen Shared)", + "features": { + "latency_ms": 423.14, + "cost_usd": 927.58, + "availability": 0.985309, + "gen_feat_1": 494.62, + "gen_feat_2": 0.504056, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_car_rental_booking_gen_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_gen_shared", + "name": "CRS.booking (Gen Shared)", + "features": { + "latency_ms": 303.36, + "cost_usd": 252.45, + "availability": 0.962251, + "gen_feat_1": 502.73, + "gen_feat_2": 0.492905, + "gen_feat_3": 511.21 + } + }, + { + "id": "t_attractions_search_gen_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions (Gen p_attractions_b)", + "features": { + "latency_ms": 183.9, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.11, + "gen_feat_2": 0.507033, + "gen_feat_3": 506.35 + } + }, + { + "id": "t_attractions_search_gen_3", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_a", + "name": "ASS.getAttractions (Gen p_dom_air_a)", + "features": { + "latency_ms": 184.86, + "cost_usd": 0.0, + "availability": 0.973261, + "gen_feat_1": 512.0, + "gen_feat_2": 0.499623, + "gen_feat_3": 508.68 + } + }, + { + "id": "t_attractions_search_gen_4", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_b", + "name": "ASS.getAttractions (Gen p_dom_air_b)", + "features": { + "latency_ms": 177.98, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.492691, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_attractions_search_gen_5", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_a", + "name": "ASS.getAttractions (Gen p_int_air_a)", + "features": { + "latency_ms": 180.31, + "cost_usd": 0.0, + "availability": 0.975329, + "gen_feat_1": 511.15, + "gen_feat_2": 0.485867, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_attractions_search_gen_6", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_b", + "name": "ASS.getAttractions (Gen p_int_air_b)", + "features": { + "latency_ms": 178.35, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 491.67, + "gen_feat_2": 0.511467, + "gen_feat_3": 505.28 + } + }, + { + "id": "t_attractions_search_gen_7", + "task_id": "t_attractions_search", + "provider_id": "p_ins_a", + "name": "ASS.getAttractions (Gen p_ins_a)", + "features": { + "latency_ms": 183.13, + "cost_usd": 0.0, + "availability": 0.982652, + "gen_feat_1": 486.89, + "gen_feat_2": 0.493076, + "gen_feat_3": 489.66 + } + }, + { + "id": "t_attractions_search_gen_8", + "task_id": "t_attractions_search", + "provider_id": "p_ins_b", + "name": "ASS.getAttractions (Gen p_ins_b)", + "features": { + "latency_ms": 176.67, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.91, + "gen_feat_2": 0.510797, + "gen_feat_3": 494.78 + } + }, + { + "id": "t_flight_booking_domestic_gen_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_a", + "name": "DFBS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 631.95, + "cost_usd": 420.96, + "availability": 0.993293, + "gen_feat_1": 509.36, + "gen_feat_2": 0.48832, + "gen_feat_3": 493.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_3", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_b", + "name": "DFBS.booking (Gen p_hotel_b)", + "features": { + "latency_ms": 657.0, + "cost_usd": 410.51, + "availability": 1.0, + "gen_feat_1": 512.88, + "gen_feat_2": 0.494914, + "gen_feat_3": 493.16 + } + }, + { + "id": "t_flight_booking_domestic_gen_4", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_a", + "name": "DFBS.booking (Gen p_car_a)", + "features": { + "latency_ms": 662.74, + "cost_usd": 432.29, + "availability": 0.955965, + "gen_feat_1": 500.97, + "gen_feat_2": 0.486536, + "gen_feat_3": 491.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_5", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_b", + "name": "DFBS.booking (Gen p_car_b)", + "features": { + "latency_ms": 660.26, + "cost_usd": 422.73, + "availability": 1.0, + "gen_feat_1": 511.72, + "gen_feat_2": 0.496489, + "gen_feat_3": 514.27 + } + }, + { + "id": "t_flight_booking_domestic_gen_6", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_1", + "name": "DFBS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 638.86, + "cost_usd": 413.02, + "availability": 0.985773, + "gen_feat_1": 498.15, + "gen_feat_2": 0.488561, + "gen_feat_3": 503.45 + } + }, + { + "id": "t_flight_booking_domestic_gen_7", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_2", + "name": "DFBS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 641.08, + "cost_usd": 429.65, + "availability": 0.978204, + "gen_feat_1": 506.04, + "gen_feat_2": 0.496573, + "gen_feat_3": 510.36 + } + }, + { + "id": "t_flight_booking_domestic_gen_8", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_3", + "name": "DFBS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 664.71, + "cost_usd": 414.68, + "availability": 0.966781, + "gen_feat_1": 489.74, + "gen_feat_2": 0.487447, + "gen_feat_3": 486.76 + } + }, + { + "id": "t_flight_booking_international_gen_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_4", + "name": "IFBS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 802.29, + "cost_usd": 805.78, + "availability": 0.988419, + "gen_feat_1": 509.12, + "gen_feat_2": 0.493932, + "gen_feat_3": 494.56 + } + }, + { + "id": "t_flight_booking_international_gen_3", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_5", + "name": "IFBS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 785.65, + "cost_usd": 832.67, + "availability": 1.0, + "gen_feat_1": 498.69, + "gen_feat_2": 0.506699, + "gen_feat_3": 486.23 + } + }, + { + "id": "t_flight_booking_international_gen_4", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_a", + "name": "IFBS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 795.93, + "cost_usd": 844.09, + "availability": 0.963688, + "gen_feat_1": 492.63, + "gen_feat_2": 0.50024, + "gen_feat_3": 503.14 + } + }, + { + "id": "t_flight_booking_international_gen_5", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_b", + "name": "IFBS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 763.55, + "cost_usd": 806.59, + "availability": 0.973216, + "gen_feat_1": 490.91, + "gen_feat_2": 0.504181, + "gen_feat_3": 493.32 + } + }, + { + "id": "t_flight_booking_international_gen_6", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_a", + "name": "IFBS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 775.31, + "cost_usd": 813.89, + "availability": 1.0, + "gen_feat_1": 514.34, + "gen_feat_2": 0.490809, + "gen_feat_3": 502.88 + } + }, + { + "id": "t_flight_booking_international_gen_7", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_b", + "name": "IFBS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 774.09, + "cost_usd": 796.86, + "availability": 1.0, + "gen_feat_1": 509.97, + "gen_feat_2": 0.50639, + "gen_feat_3": 488.65 + } + }, + { + "id": "t_flight_booking_international_gen_8", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 802.89, + "cost_usd": 832.54, + "availability": 0.995867, + "gen_feat_1": 500.61, + "gen_feat_2": 0.492753, + "gen_feat_3": 489.35 + } + }, + { + "id": "t_travel_insurance_gen_2", + "task_id": "t_travel_insurance", + "provider_id": "p_int_air_b", + "name": "TIS.getInsurance (Gen p_int_air_b)", + "features": { + "latency_ms": 239.89, + "cost_usd": 54.54, + "availability": 0.978354, + "gen_feat_1": 504.59, + "gen_feat_2": 0.502031, + "gen_feat_3": 500.67 + } + }, + { + "id": "t_travel_insurance_gen_3", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance (Gen p_ins_a)", + "features": { + "latency_ms": 235.94, + "cost_usd": 55.24, + "availability": 1.0, + "gen_feat_1": 510.78, + "gen_feat_2": 0.49515, + "gen_feat_3": 514.3 + } + }, + { + "id": "t_travel_insurance_gen_4", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance (Gen p_ins_b)", + "features": { + "latency_ms": 239.19, + "cost_usd": 54.65, + "availability": 0.97242, + "gen_feat_1": 493.99, + "gen_feat_2": 0.507973, + "gen_feat_3": 491.39 + } + }, + { + "id": "t_travel_insurance_gen_5", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_a", + "name": "TIS.getInsurance (Gen p_hotel_a)", + "features": { + "latency_ms": 237.46, + "cost_usd": 55.4, + "availability": 1.0, + "gen_feat_1": 502.98, + "gen_feat_2": 0.490074, + "gen_feat_3": 504.05 + } + }, + { + "id": "t_travel_insurance_gen_6", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_b", + "name": "TIS.getInsurance (Gen p_hotel_b)", + "features": { + "latency_ms": 246.8, + "cost_usd": 55.95, + "availability": 0.997177, + "gen_feat_1": 498.91, + "gen_feat_2": 0.494214, + "gen_feat_3": 502.98 + } + }, + { + "id": "t_travel_insurance_gen_7", + "task_id": "t_travel_insurance", + "provider_id": "p_car_a", + "name": "TIS.getInsurance (Gen p_car_a)", + "features": { + "latency_ms": 246.54, + "cost_usd": 54.9, + "availability": 0.99944, + "gen_feat_1": 492.97, + "gen_feat_2": 0.512985, + "gen_feat_3": 497.1 + } + }, + { + "id": "t_travel_insurance_gen_8", + "task_id": "t_travel_insurance", + "provider_id": "p_car_b", + "name": "TIS.getInsurance (Gen p_car_b)", + "features": { + "latency_ms": 245.14, + "cost_usd": 53.91, + "availability": 1.0, + "gen_feat_1": 507.6, + "gen_feat_2": 0.491973, + "gen_feat_3": 489.42 + } + }, + { + "id": "t_accommodation_booking_gen_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_1", + "name": "ABS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 417.7, + "cost_usd": 957.65, + "availability": 1.0, + "gen_feat_1": 491.17, + "gen_feat_2": 0.487995, + "gen_feat_3": 496.04 + } + }, + { + "id": "t_accommodation_booking_gen_3", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_2", + "name": "ABS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 435.3, + "cost_usd": 943.55, + "availability": 0.98734, + "gen_feat_1": 490.66, + "gen_feat_2": 0.512804, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_accommodation_booking_gen_4", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_3", + "name": "ABS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 424.85, + "cost_usd": 946.36, + "availability": 0.983088, + "gen_feat_1": 490.8, + "gen_feat_2": 0.498715, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_accommodation_booking_gen_5", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_4", + "name": "ABS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 437.83, + "cost_usd": 931.98, + "availability": 0.989306, + "gen_feat_1": 486.79, + "gen_feat_2": 0.511194, + "gen_feat_3": 509.55 + } + }, + { + "id": "t_accommodation_booking_gen_6", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_5", + "name": "ABS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 441.94, + "cost_usd": 938.72, + "availability": 1.0, + "gen_feat_1": 500.85, + "gen_feat_2": 0.494949, + "gen_feat_3": 494.14 + } + }, + { + "id": "t_accommodation_booking_gen_7", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_a", + "name": "ABS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 438.16, + "cost_usd": 938.79, + "availability": 1.0, + "gen_feat_1": 485.27, + "gen_feat_2": 0.498913, + "gen_feat_3": 487.12 + } + }, + { + "id": "t_accommodation_booking_gen_8", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_b", + "name": "ABS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 418.07, + "cost_usd": 922.82, + "availability": 1.0, + "gen_feat_1": 497.81, + "gen_feat_2": 0.502515, + "gen_feat_3": 509.16 + } + }, + { + "id": "t_car_rental_booking_gen_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_a", + "name": "CRS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 312.13, + "cost_usd": 261.53, + "availability": 1.0, + "gen_feat_1": 512.64, + "gen_feat_2": 0.496089, + "gen_feat_3": 504.19 + } + }, + { + "id": "t_car_rental_booking_gen_3", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_b", + "name": "CRS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 313.91, + "cost_usd": 257.49, + "availability": 0.98681, + "gen_feat_1": 512.87, + "gen_feat_2": 0.505241, + "gen_feat_3": 507.29 + } + }, + { + "id": "t_car_rental_booking_gen_4", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_a", + "name": "CRS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 302.5, + "cost_usd": 253.26, + "availability": 0.988174, + "gen_feat_1": 486.1, + "gen_feat_2": 0.485054, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_car_rental_booking_gen_5", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_b", + "name": "CRS.booking (Gen p_int_air_b)", + "features": { + "latency_ms": 318.31, + "cost_usd": 266.75, + "availability": 0.978032, + "gen_feat_1": 497.95, + "gen_feat_2": 0.49628, + "gen_feat_3": 508.32 + } + }, + { + "id": "t_car_rental_booking_gen_6", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_a", + "name": "CRS.booking (Gen p_ins_a)", + "features": { + "latency_ms": 315.37, + "cost_usd": 257.45, + "availability": 0.991843, + "gen_feat_1": 510.59, + "gen_feat_2": 0.501464, + "gen_feat_3": 495.6 + } + }, + { + "id": "t_car_rental_booking_gen_7", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_b", + "name": "CRS.booking (Gen p_ins_b)", + "features": { + "latency_ms": 311.72, + "cost_usd": 255.51, + "availability": 0.984838, + "gen_feat_1": 498.99, + "gen_feat_2": 0.505672, + "gen_feat_3": 506.54 + } + }, + { + "id": "t_car_rental_booking_gen_8", + "task_id": "t_car_rental_booking", + "provider_id": "p_hotel_a", + "name": "CRS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 306.59, + "cost_usd": 258.27, + "availability": 1.0, + "gen_feat_1": 512.19, + "gen_feat_2": 0.506375, + "gen_feat_3": 513.91 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_parallel", + "kind": "AND", + "children": [ + { + "id": "n_as", + "kind": "TASK", + "task_id": "t_attractions_search" + }, + { + "id": "n_booking_flow", + "kind": "SEQ", + "children": [ + { + "id": "n_flight_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.6, + "child": { + "id": "n_dfb", + "kind": "TASK", + "task_id": "t_flight_booking_domestic" + } + }, + { + "p": 0.4, + "child": { + "id": "n_intl_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_ifb", + "kind": "TASK", + "task_id": "t_flight_booking_international" + }, + { + "id": "n_ti", + "kind": "TASK", + "task_id": "t_travel_insurance" + } + ] + } + } + ] + }, + { + "id": "n_ab", + "kind": "TASK", + "task_id": "t_accommodation_booking" + } + ] + } + ] + }, + { + "id": "n_car_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.3, + "child": { + "id": "n_cr", + "kind": "TASK", + "task_id": "t_car_rental_booking" + } + }, + { + "p": 0.7, + "child": { + "id": "n_no_car", + "kind": "ELEMENT", + "description": "Skip car rental (represents the near(...) branch)" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1301.98, + "hard": true + }, + { + "id": "gen_c_local_t_accommodation_booking_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_accommodation_booking" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 927.58, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_attractions_search" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_car_rental_booking" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_mono_utility_soft.json b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_mono_utility_soft.json new file mode 100644 index 0000000..d157856 --- /dev/null +++ b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_mono_utility_soft.json @@ -0,0 +1,1278 @@ +{ + "metadata": { + "id": "benatallah2002-selfserv-travel-solution-cts-itas_mono_utility_soft", + "name": "Travel Solution (Benatallah et al. 2002) [mono_utility, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from the SELF-SERV running example (CTS and ITAS statecharts). QoS values and branch probabilities are illustrative because the paper does not provide numeric QoS.", + "paper": { + "title": "Declarative Compositionand Peer-to-PeerProvisioning of Dynamic WebServices", + "authors": "B. Benatallah et al.", + "year": 2002, + "doi": "10.5555/876875.878987" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Total price charged to customer", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "availability", + "name": "Probability the service invocation succeeds", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_attractions_a", + "name": "AttractionsSearch Provider A" + }, + { + "id": "p_attractions_b", + "name": "AttractionsSearch Provider B" + }, + { + "id": "p_dom_air_a", + "name": "Domestic Airline A" + }, + { + "id": "p_dom_air_b", + "name": "Domestic Airline B" + }, + { + "id": "p_int_air_a", + "name": "International Airline A" + }, + { + "id": "p_int_air_b", + "name": "International Airline B" + }, + { + "id": "p_ins_a", + "name": "Travel Insurance Co. A" + }, + { + "id": "p_ins_b", + "name": "Travel Insurance Co. B" + }, + { + "id": "p_hotel_a", + "name": "Accommodation Provider A" + }, + { + "id": "p_hotel_b", + "name": "Accommodation Provider B" + }, + { + "id": "p_car_a", + "name": "Car Rental Provider A" + }, + { + "id": "p_car_b", + "name": "Car Rental Provider B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_attractions_search", + "name": "Attractions Search (ASS.getAttractions)" + }, + { + "id": "t_flight_booking_domestic", + "name": "Domestic Flight Booking (DFBS.booking)" + }, + { + "id": "t_flight_booking_international", + "name": "International Flight Booking (IFBS.booking)" + }, + { + "id": "t_travel_insurance", + "name": "Travel Insurance (TIS.getInsurance)" + }, + { + "id": "t_accommodation_booking", + "name": "Accommodation Booking (ABS.booking)" + }, + { + "id": "t_car_rental_booking", + "name": "Car Rental Booking (CRS.booking)" + } + ], + "candidates": [ + { + "id": "svc_ass_1", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_a", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 180, + "cost_usd": 0, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ass_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 120, + "cost_usd": 5, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_a", + "name": "DFBS.booking", + "features": { + "latency_ms": 650, + "cost_usd": 420, + "availability": 0.985, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_b", + "name": "DFBS.booking", + "features": { + "latency_ms": 520, + "cost_usd": 460, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking", + "features": { + "latency_ms": 780, + "cost_usd": 820, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_b", + "name": "IFBS.booking", + "features": { + "latency_ms": 610, + "cost_usd": 900, + "availability": 0.988, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_1", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 240, + "cost_usd": 55, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_2", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 190, + "cost_usd": 70, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_a", + "name": "ABS.booking", + "features": { + "latency_ms": 430, + "cost_usd": 950, + "availability": 0.992, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_b", + "name": "ABS.booking", + "features": { + "latency_ms": 350, + "cost_usd": 1100, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_a", + "name": "CRS.booking", + "features": { + "latency_ms": 310, + "cost_usd": 260, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_b", + "name": "CRS.booking", + "features": { + "latency_ms": 260, + "cost_usd": 320, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_attractions_search_gen_1", + "task_id": "t_attractions_search", + "provider_id": "p_gen_shared", + "name": "ASS.getAttractions (Gen Shared)", + "features": { + "latency_ms": 180.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.57, + "gen_feat_2": 0.493935, + "gen_feat_3": 485.71 + } + }, + { + "id": "t_flight_booking_domestic_gen_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_shared", + "name": "DFBS.booking (Gen Shared)", + "features": { + "latency_ms": 647.32, + "cost_usd": 411.46, + "availability": 0.979506, + "gen_feat_1": 505.68, + "gen_feat_2": 0.506905, + "gen_feat_3": 510.18 + } + }, + { + "id": "t_flight_booking_international_gen_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_shared", + "name": "IFBS.booking (Gen Shared)", + "features": { + "latency_ms": 759.62, + "cost_usd": 814.07, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.503149, + "gen_feat_3": 501.18 + } + }, + { + "id": "t_travel_insurance_gen_1", + "task_id": "t_travel_insurance", + "provider_id": "p_gen_shared", + "name": "TIS.getInsurance (Gen Shared)", + "features": { + "latency_ms": 234.01, + "cost_usd": 55.73, + "availability": 0.994473, + "gen_feat_1": 505.2, + "gen_feat_2": 0.498515, + "gen_feat_3": 487.21 + } + }, + { + "id": "t_accommodation_booking_gen_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_shared", + "name": "ABS.booking (Gen Shared)", + "features": { + "latency_ms": 423.14, + "cost_usd": 927.58, + "availability": 0.985309, + "gen_feat_1": 494.62, + "gen_feat_2": 0.504056, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_car_rental_booking_gen_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_gen_shared", + "name": "CRS.booking (Gen Shared)", + "features": { + "latency_ms": 303.36, + "cost_usd": 252.45, + "availability": 0.962251, + "gen_feat_1": 502.73, + "gen_feat_2": 0.492905, + "gen_feat_3": 511.21 + } + }, + { + "id": "t_attractions_search_gen_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions (Gen p_attractions_b)", + "features": { + "latency_ms": 183.9, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.11, + "gen_feat_2": 0.507033, + "gen_feat_3": 506.35 + } + }, + { + "id": "t_attractions_search_gen_3", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_a", + "name": "ASS.getAttractions (Gen p_dom_air_a)", + "features": { + "latency_ms": 184.86, + "cost_usd": 0.0, + "availability": 0.973261, + "gen_feat_1": 512.0, + "gen_feat_2": 0.499623, + "gen_feat_3": 508.68 + } + }, + { + "id": "t_attractions_search_gen_4", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_b", + "name": "ASS.getAttractions (Gen p_dom_air_b)", + "features": { + "latency_ms": 177.98, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.492691, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_attractions_search_gen_5", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_a", + "name": "ASS.getAttractions (Gen p_int_air_a)", + "features": { + "latency_ms": 180.31, + "cost_usd": 0.0, + "availability": 0.975329, + "gen_feat_1": 511.15, + "gen_feat_2": 0.485867, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_attractions_search_gen_6", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_b", + "name": "ASS.getAttractions (Gen p_int_air_b)", + "features": { + "latency_ms": 178.35, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 491.67, + "gen_feat_2": 0.511467, + "gen_feat_3": 505.28 + } + }, + { + "id": "t_attractions_search_gen_7", + "task_id": "t_attractions_search", + "provider_id": "p_ins_a", + "name": "ASS.getAttractions (Gen p_ins_a)", + "features": { + "latency_ms": 183.13, + "cost_usd": 0.0, + "availability": 0.982652, + "gen_feat_1": 486.89, + "gen_feat_2": 0.493076, + "gen_feat_3": 489.66 + } + }, + { + "id": "t_attractions_search_gen_8", + "task_id": "t_attractions_search", + "provider_id": "p_ins_b", + "name": "ASS.getAttractions (Gen p_ins_b)", + "features": { + "latency_ms": 176.67, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.91, + "gen_feat_2": 0.510797, + "gen_feat_3": 494.78 + } + }, + { + "id": "t_flight_booking_domestic_gen_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_a", + "name": "DFBS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 631.95, + "cost_usd": 420.96, + "availability": 0.993293, + "gen_feat_1": 509.36, + "gen_feat_2": 0.48832, + "gen_feat_3": 493.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_3", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_b", + "name": "DFBS.booking (Gen p_hotel_b)", + "features": { + "latency_ms": 657.0, + "cost_usd": 410.51, + "availability": 1.0, + "gen_feat_1": 512.88, + "gen_feat_2": 0.494914, + "gen_feat_3": 493.16 + } + }, + { + "id": "t_flight_booking_domestic_gen_4", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_a", + "name": "DFBS.booking (Gen p_car_a)", + "features": { + "latency_ms": 662.74, + "cost_usd": 432.29, + "availability": 0.955965, + "gen_feat_1": 500.97, + "gen_feat_2": 0.486536, + "gen_feat_3": 491.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_5", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_b", + "name": "DFBS.booking (Gen p_car_b)", + "features": { + "latency_ms": 660.26, + "cost_usd": 422.73, + "availability": 1.0, + "gen_feat_1": 511.72, + "gen_feat_2": 0.496489, + "gen_feat_3": 514.27 + } + }, + { + "id": "t_flight_booking_domestic_gen_6", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_1", + "name": "DFBS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 638.86, + "cost_usd": 413.02, + "availability": 0.985773, + "gen_feat_1": 498.15, + "gen_feat_2": 0.488561, + "gen_feat_3": 503.45 + } + }, + { + "id": "t_flight_booking_domestic_gen_7", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_2", + "name": "DFBS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 641.08, + "cost_usd": 429.65, + "availability": 0.978204, + "gen_feat_1": 506.04, + "gen_feat_2": 0.496573, + "gen_feat_3": 510.36 + } + }, + { + "id": "t_flight_booking_domestic_gen_8", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_3", + "name": "DFBS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 664.71, + "cost_usd": 414.68, + "availability": 0.966781, + "gen_feat_1": 489.74, + "gen_feat_2": 0.487447, + "gen_feat_3": 486.76 + } + }, + { + "id": "t_flight_booking_international_gen_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_4", + "name": "IFBS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 802.29, + "cost_usd": 805.78, + "availability": 0.988419, + "gen_feat_1": 509.12, + "gen_feat_2": 0.493932, + "gen_feat_3": 494.56 + } + }, + { + "id": "t_flight_booking_international_gen_3", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_5", + "name": "IFBS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 785.65, + "cost_usd": 832.67, + "availability": 1.0, + "gen_feat_1": 498.69, + "gen_feat_2": 0.506699, + "gen_feat_3": 486.23 + } + }, + { + "id": "t_flight_booking_international_gen_4", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_a", + "name": "IFBS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 795.93, + "cost_usd": 844.09, + "availability": 0.963688, + "gen_feat_1": 492.63, + "gen_feat_2": 0.50024, + "gen_feat_3": 503.14 + } + }, + { + "id": "t_flight_booking_international_gen_5", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_b", + "name": "IFBS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 763.55, + "cost_usd": 806.59, + "availability": 0.973216, + "gen_feat_1": 490.91, + "gen_feat_2": 0.504181, + "gen_feat_3": 493.32 + } + }, + { + "id": "t_flight_booking_international_gen_6", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_a", + "name": "IFBS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 775.31, + "cost_usd": 813.89, + "availability": 1.0, + "gen_feat_1": 514.34, + "gen_feat_2": 0.490809, + "gen_feat_3": 502.88 + } + }, + { + "id": "t_flight_booking_international_gen_7", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_b", + "name": "IFBS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 774.09, + "cost_usd": 796.86, + "availability": 1.0, + "gen_feat_1": 509.97, + "gen_feat_2": 0.50639, + "gen_feat_3": 488.65 + } + }, + { + "id": "t_flight_booking_international_gen_8", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 802.89, + "cost_usd": 832.54, + "availability": 0.995867, + "gen_feat_1": 500.61, + "gen_feat_2": 0.492753, + "gen_feat_3": 489.35 + } + }, + { + "id": "t_travel_insurance_gen_2", + "task_id": "t_travel_insurance", + "provider_id": "p_int_air_b", + "name": "TIS.getInsurance (Gen p_int_air_b)", + "features": { + "latency_ms": 239.89, + "cost_usd": 54.54, + "availability": 0.978354, + "gen_feat_1": 504.59, + "gen_feat_2": 0.502031, + "gen_feat_3": 500.67 + } + }, + { + "id": "t_travel_insurance_gen_3", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance (Gen p_ins_a)", + "features": { + "latency_ms": 235.94, + "cost_usd": 55.24, + "availability": 1.0, + "gen_feat_1": 510.78, + "gen_feat_2": 0.49515, + "gen_feat_3": 514.3 + } + }, + { + "id": "t_travel_insurance_gen_4", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance (Gen p_ins_b)", + "features": { + "latency_ms": 239.19, + "cost_usd": 54.65, + "availability": 0.97242, + "gen_feat_1": 493.99, + "gen_feat_2": 0.507973, + "gen_feat_3": 491.39 + } + }, + { + "id": "t_travel_insurance_gen_5", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_a", + "name": "TIS.getInsurance (Gen p_hotel_a)", + "features": { + "latency_ms": 237.46, + "cost_usd": 55.4, + "availability": 1.0, + "gen_feat_1": 502.98, + "gen_feat_2": 0.490074, + "gen_feat_3": 504.05 + } + }, + { + "id": "t_travel_insurance_gen_6", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_b", + "name": "TIS.getInsurance (Gen p_hotel_b)", + "features": { + "latency_ms": 246.8, + "cost_usd": 55.95, + "availability": 0.997177, + "gen_feat_1": 498.91, + "gen_feat_2": 0.494214, + "gen_feat_3": 502.98 + } + }, + { + "id": "t_travel_insurance_gen_7", + "task_id": "t_travel_insurance", + "provider_id": "p_car_a", + "name": "TIS.getInsurance (Gen p_car_a)", + "features": { + "latency_ms": 246.54, + "cost_usd": 54.9, + "availability": 0.99944, + "gen_feat_1": 492.97, + "gen_feat_2": 0.512985, + "gen_feat_3": 497.1 + } + }, + { + "id": "t_travel_insurance_gen_8", + "task_id": "t_travel_insurance", + "provider_id": "p_car_b", + "name": "TIS.getInsurance (Gen p_car_b)", + "features": { + "latency_ms": 245.14, + "cost_usd": 53.91, + "availability": 1.0, + "gen_feat_1": 507.6, + "gen_feat_2": 0.491973, + "gen_feat_3": 489.42 + } + }, + { + "id": "t_accommodation_booking_gen_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_1", + "name": "ABS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 417.7, + "cost_usd": 957.65, + "availability": 1.0, + "gen_feat_1": 491.17, + "gen_feat_2": 0.487995, + "gen_feat_3": 496.04 + } + }, + { + "id": "t_accommodation_booking_gen_3", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_2", + "name": "ABS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 435.3, + "cost_usd": 943.55, + "availability": 0.98734, + "gen_feat_1": 490.66, + "gen_feat_2": 0.512804, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_accommodation_booking_gen_4", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_3", + "name": "ABS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 424.85, + "cost_usd": 946.36, + "availability": 0.983088, + "gen_feat_1": 490.8, + "gen_feat_2": 0.498715, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_accommodation_booking_gen_5", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_4", + "name": "ABS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 437.83, + "cost_usd": 931.98, + "availability": 0.989306, + "gen_feat_1": 486.79, + "gen_feat_2": 0.511194, + "gen_feat_3": 509.55 + } + }, + { + "id": "t_accommodation_booking_gen_6", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_5", + "name": "ABS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 441.94, + "cost_usd": 938.72, + "availability": 1.0, + "gen_feat_1": 500.85, + "gen_feat_2": 0.494949, + "gen_feat_3": 494.14 + } + }, + { + "id": "t_accommodation_booking_gen_7", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_a", + "name": "ABS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 438.16, + "cost_usd": 938.79, + "availability": 1.0, + "gen_feat_1": 485.27, + "gen_feat_2": 0.498913, + "gen_feat_3": 487.12 + } + }, + { + "id": "t_accommodation_booking_gen_8", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_b", + "name": "ABS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 418.07, + "cost_usd": 922.82, + "availability": 1.0, + "gen_feat_1": 497.81, + "gen_feat_2": 0.502515, + "gen_feat_3": 509.16 + } + }, + { + "id": "t_car_rental_booking_gen_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_a", + "name": "CRS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 312.13, + "cost_usd": 261.53, + "availability": 1.0, + "gen_feat_1": 512.64, + "gen_feat_2": 0.496089, + "gen_feat_3": 504.19 + } + }, + { + "id": "t_car_rental_booking_gen_3", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_b", + "name": "CRS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 313.91, + "cost_usd": 257.49, + "availability": 0.98681, + "gen_feat_1": 512.87, + "gen_feat_2": 0.505241, + "gen_feat_3": 507.29 + } + }, + { + "id": "t_car_rental_booking_gen_4", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_a", + "name": "CRS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 302.5, + "cost_usd": 253.26, + "availability": 0.988174, + "gen_feat_1": 486.1, + "gen_feat_2": 0.485054, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_car_rental_booking_gen_5", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_b", + "name": "CRS.booking (Gen p_int_air_b)", + "features": { + "latency_ms": 318.31, + "cost_usd": 266.75, + "availability": 0.978032, + "gen_feat_1": 497.95, + "gen_feat_2": 0.49628, + "gen_feat_3": 508.32 + } + }, + { + "id": "t_car_rental_booking_gen_6", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_a", + "name": "CRS.booking (Gen p_ins_a)", + "features": { + "latency_ms": 315.37, + "cost_usd": 257.45, + "availability": 0.991843, + "gen_feat_1": 510.59, + "gen_feat_2": 0.501464, + "gen_feat_3": 495.6 + } + }, + { + "id": "t_car_rental_booking_gen_7", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_b", + "name": "CRS.booking (Gen p_ins_b)", + "features": { + "latency_ms": 311.72, + "cost_usd": 255.51, + "availability": 0.984838, + "gen_feat_1": 498.99, + "gen_feat_2": 0.505672, + "gen_feat_3": 506.54 + } + }, + { + "id": "t_car_rental_booking_gen_8", + "task_id": "t_car_rental_booking", + "provider_id": "p_hotel_a", + "name": "CRS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 306.59, + "cost_usd": 258.27, + "availability": 1.0, + "gen_feat_1": 512.19, + "gen_feat_2": 0.506375, + "gen_feat_3": 513.91 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_parallel", + "kind": "AND", + "children": [ + { + "id": "n_as", + "kind": "TASK", + "task_id": "t_attractions_search" + }, + { + "id": "n_booking_flow", + "kind": "SEQ", + "children": [ + { + "id": "n_flight_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.6, + "child": { + "id": "n_dfb", + "kind": "TASK", + "task_id": "t_flight_booking_domestic" + } + }, + { + "p": 0.4, + "child": { + "id": "n_intl_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_ifb", + "kind": "TASK", + "task_id": "t_flight_booking_international" + }, + { + "id": "n_ti", + "kind": "TASK", + "task_id": "t_travel_insurance" + } + ] + } + } + ] + }, + { + "id": "n_ab", + "kind": "TASK", + "task_id": "t_accommodation_booking" + } + ] + } + ] + }, + { + "id": "n_car_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.3, + "child": { + "id": "n_cr", + "kind": "TASK", + "task_id": "t_car_rental_booking" + } + }, + { + "p": 0.7, + "child": { + "id": "n_no_car", + "kind": "ELEMENT", + "description": "Skip car rental (represents the near(...) branch)" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1301.98, + "hard": false + }, + { + "id": "gen_c_local_t_accommodation_booking_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_accommodation_booking" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 927.58, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_attractions_search" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_car_rental_booking" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_multi_hard.json b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_multi_hard.json new file mode 100644 index 0000000..2abe232 --- /dev/null +++ b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_multi_hard.json @@ -0,0 +1,1272 @@ +{ + "metadata": { + "id": "benatallah2002-selfserv-travel-solution-cts-itas_multi_hard", + "name": "Travel Solution (Benatallah et al. 2002) [multi, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from the SELF-SERV running example (CTS and ITAS statecharts). QoS values and branch probabilities are illustrative because the paper does not provide numeric QoS.", + "paper": { + "title": "Declarative Compositionand Peer-to-PeerProvisioning of Dynamic WebServices", + "authors": "B. Benatallah et al.", + "year": 2002, + "doi": "10.5555/876875.878987" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Total price charged to customer", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "availability", + "name": "Probability the service invocation succeeds", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_attractions_a", + "name": "AttractionsSearch Provider A" + }, + { + "id": "p_attractions_b", + "name": "AttractionsSearch Provider B" + }, + { + "id": "p_dom_air_a", + "name": "Domestic Airline A" + }, + { + "id": "p_dom_air_b", + "name": "Domestic Airline B" + }, + { + "id": "p_int_air_a", + "name": "International Airline A" + }, + { + "id": "p_int_air_b", + "name": "International Airline B" + }, + { + "id": "p_ins_a", + "name": "Travel Insurance Co. A" + }, + { + "id": "p_ins_b", + "name": "Travel Insurance Co. B" + }, + { + "id": "p_hotel_a", + "name": "Accommodation Provider A" + }, + { + "id": "p_hotel_b", + "name": "Accommodation Provider B" + }, + { + "id": "p_car_a", + "name": "Car Rental Provider A" + }, + { + "id": "p_car_b", + "name": "Car Rental Provider B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_attractions_search", + "name": "Attractions Search (ASS.getAttractions)" + }, + { + "id": "t_flight_booking_domestic", + "name": "Domestic Flight Booking (DFBS.booking)" + }, + { + "id": "t_flight_booking_international", + "name": "International Flight Booking (IFBS.booking)" + }, + { + "id": "t_travel_insurance", + "name": "Travel Insurance (TIS.getInsurance)" + }, + { + "id": "t_accommodation_booking", + "name": "Accommodation Booking (ABS.booking)" + }, + { + "id": "t_car_rental_booking", + "name": "Car Rental Booking (CRS.booking)" + } + ], + "candidates": [ + { + "id": "svc_ass_1", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_a", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 180, + "cost_usd": 0, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ass_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 120, + "cost_usd": 5, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_a", + "name": "DFBS.booking", + "features": { + "latency_ms": 650, + "cost_usd": 420, + "availability": 0.985, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_b", + "name": "DFBS.booking", + "features": { + "latency_ms": 520, + "cost_usd": 460, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking", + "features": { + "latency_ms": 780, + "cost_usd": 820, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_b", + "name": "IFBS.booking", + "features": { + "latency_ms": 610, + "cost_usd": 900, + "availability": 0.988, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_1", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 240, + "cost_usd": 55, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_2", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 190, + "cost_usd": 70, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_a", + "name": "ABS.booking", + "features": { + "latency_ms": 430, + "cost_usd": 950, + "availability": 0.992, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_b", + "name": "ABS.booking", + "features": { + "latency_ms": 350, + "cost_usd": 1100, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_a", + "name": "CRS.booking", + "features": { + "latency_ms": 310, + "cost_usd": 260, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_b", + "name": "CRS.booking", + "features": { + "latency_ms": 260, + "cost_usd": 320, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_attractions_search_gen_1", + "task_id": "t_attractions_search", + "provider_id": "p_gen_shared", + "name": "ASS.getAttractions (Gen Shared)", + "features": { + "latency_ms": 180.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.57, + "gen_feat_2": 0.493935, + "gen_feat_3": 485.71 + } + }, + { + "id": "t_flight_booking_domestic_gen_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_shared", + "name": "DFBS.booking (Gen Shared)", + "features": { + "latency_ms": 647.32, + "cost_usd": 411.46, + "availability": 0.979506, + "gen_feat_1": 505.68, + "gen_feat_2": 0.506905, + "gen_feat_3": 510.18 + } + }, + { + "id": "t_flight_booking_international_gen_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_shared", + "name": "IFBS.booking (Gen Shared)", + "features": { + "latency_ms": 759.62, + "cost_usd": 814.07, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.503149, + "gen_feat_3": 501.18 + } + }, + { + "id": "t_travel_insurance_gen_1", + "task_id": "t_travel_insurance", + "provider_id": "p_gen_shared", + "name": "TIS.getInsurance (Gen Shared)", + "features": { + "latency_ms": 234.01, + "cost_usd": 55.73, + "availability": 0.994473, + "gen_feat_1": 505.2, + "gen_feat_2": 0.498515, + "gen_feat_3": 487.21 + } + }, + { + "id": "t_accommodation_booking_gen_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_shared", + "name": "ABS.booking (Gen Shared)", + "features": { + "latency_ms": 423.14, + "cost_usd": 927.58, + "availability": 0.985309, + "gen_feat_1": 494.62, + "gen_feat_2": 0.504056, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_car_rental_booking_gen_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_gen_shared", + "name": "CRS.booking (Gen Shared)", + "features": { + "latency_ms": 303.36, + "cost_usd": 252.45, + "availability": 0.962251, + "gen_feat_1": 502.73, + "gen_feat_2": 0.492905, + "gen_feat_3": 511.21 + } + }, + { + "id": "t_attractions_search_gen_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions (Gen p_attractions_b)", + "features": { + "latency_ms": 183.9, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.11, + "gen_feat_2": 0.507033, + "gen_feat_3": 506.35 + } + }, + { + "id": "t_attractions_search_gen_3", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_a", + "name": "ASS.getAttractions (Gen p_dom_air_a)", + "features": { + "latency_ms": 184.86, + "cost_usd": 0.0, + "availability": 0.973261, + "gen_feat_1": 512.0, + "gen_feat_2": 0.499623, + "gen_feat_3": 508.68 + } + }, + { + "id": "t_attractions_search_gen_4", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_b", + "name": "ASS.getAttractions (Gen p_dom_air_b)", + "features": { + "latency_ms": 177.98, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.492691, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_attractions_search_gen_5", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_a", + "name": "ASS.getAttractions (Gen p_int_air_a)", + "features": { + "latency_ms": 180.31, + "cost_usd": 0.0, + "availability": 0.975329, + "gen_feat_1": 511.15, + "gen_feat_2": 0.485867, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_attractions_search_gen_6", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_b", + "name": "ASS.getAttractions (Gen p_int_air_b)", + "features": { + "latency_ms": 178.35, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 491.67, + "gen_feat_2": 0.511467, + "gen_feat_3": 505.28 + } + }, + { + "id": "t_attractions_search_gen_7", + "task_id": "t_attractions_search", + "provider_id": "p_ins_a", + "name": "ASS.getAttractions (Gen p_ins_a)", + "features": { + "latency_ms": 183.13, + "cost_usd": 0.0, + "availability": 0.982652, + "gen_feat_1": 486.89, + "gen_feat_2": 0.493076, + "gen_feat_3": 489.66 + } + }, + { + "id": "t_attractions_search_gen_8", + "task_id": "t_attractions_search", + "provider_id": "p_ins_b", + "name": "ASS.getAttractions (Gen p_ins_b)", + "features": { + "latency_ms": 176.67, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.91, + "gen_feat_2": 0.510797, + "gen_feat_3": 494.78 + } + }, + { + "id": "t_flight_booking_domestic_gen_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_a", + "name": "DFBS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 631.95, + "cost_usd": 420.96, + "availability": 0.993293, + "gen_feat_1": 509.36, + "gen_feat_2": 0.48832, + "gen_feat_3": 493.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_3", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_b", + "name": "DFBS.booking (Gen p_hotel_b)", + "features": { + "latency_ms": 657.0, + "cost_usd": 410.51, + "availability": 1.0, + "gen_feat_1": 512.88, + "gen_feat_2": 0.494914, + "gen_feat_3": 493.16 + } + }, + { + "id": "t_flight_booking_domestic_gen_4", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_a", + "name": "DFBS.booking (Gen p_car_a)", + "features": { + "latency_ms": 662.74, + "cost_usd": 432.29, + "availability": 0.955965, + "gen_feat_1": 500.97, + "gen_feat_2": 0.486536, + "gen_feat_3": 491.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_5", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_b", + "name": "DFBS.booking (Gen p_car_b)", + "features": { + "latency_ms": 660.26, + "cost_usd": 422.73, + "availability": 1.0, + "gen_feat_1": 511.72, + "gen_feat_2": 0.496489, + "gen_feat_3": 514.27 + } + }, + { + "id": "t_flight_booking_domestic_gen_6", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_1", + "name": "DFBS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 638.86, + "cost_usd": 413.02, + "availability": 0.985773, + "gen_feat_1": 498.15, + "gen_feat_2": 0.488561, + "gen_feat_3": 503.45 + } + }, + { + "id": "t_flight_booking_domestic_gen_7", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_2", + "name": "DFBS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 641.08, + "cost_usd": 429.65, + "availability": 0.978204, + "gen_feat_1": 506.04, + "gen_feat_2": 0.496573, + "gen_feat_3": 510.36 + } + }, + { + "id": "t_flight_booking_domestic_gen_8", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_3", + "name": "DFBS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 664.71, + "cost_usd": 414.68, + "availability": 0.966781, + "gen_feat_1": 489.74, + "gen_feat_2": 0.487447, + "gen_feat_3": 486.76 + } + }, + { + "id": "t_flight_booking_international_gen_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_4", + "name": "IFBS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 802.29, + "cost_usd": 805.78, + "availability": 0.988419, + "gen_feat_1": 509.12, + "gen_feat_2": 0.493932, + "gen_feat_3": 494.56 + } + }, + { + "id": "t_flight_booking_international_gen_3", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_5", + "name": "IFBS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 785.65, + "cost_usd": 832.67, + "availability": 1.0, + "gen_feat_1": 498.69, + "gen_feat_2": 0.506699, + "gen_feat_3": 486.23 + } + }, + { + "id": "t_flight_booking_international_gen_4", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_a", + "name": "IFBS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 795.93, + "cost_usd": 844.09, + "availability": 0.963688, + "gen_feat_1": 492.63, + "gen_feat_2": 0.50024, + "gen_feat_3": 503.14 + } + }, + { + "id": "t_flight_booking_international_gen_5", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_b", + "name": "IFBS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 763.55, + "cost_usd": 806.59, + "availability": 0.973216, + "gen_feat_1": 490.91, + "gen_feat_2": 0.504181, + "gen_feat_3": 493.32 + } + }, + { + "id": "t_flight_booking_international_gen_6", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_a", + "name": "IFBS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 775.31, + "cost_usd": 813.89, + "availability": 1.0, + "gen_feat_1": 514.34, + "gen_feat_2": 0.490809, + "gen_feat_3": 502.88 + } + }, + { + "id": "t_flight_booking_international_gen_7", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_b", + "name": "IFBS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 774.09, + "cost_usd": 796.86, + "availability": 1.0, + "gen_feat_1": 509.97, + "gen_feat_2": 0.50639, + "gen_feat_3": 488.65 + } + }, + { + "id": "t_flight_booking_international_gen_8", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 802.89, + "cost_usd": 832.54, + "availability": 0.995867, + "gen_feat_1": 500.61, + "gen_feat_2": 0.492753, + "gen_feat_3": 489.35 + } + }, + { + "id": "t_travel_insurance_gen_2", + "task_id": "t_travel_insurance", + "provider_id": "p_int_air_b", + "name": "TIS.getInsurance (Gen p_int_air_b)", + "features": { + "latency_ms": 239.89, + "cost_usd": 54.54, + "availability": 0.978354, + "gen_feat_1": 504.59, + "gen_feat_2": 0.502031, + "gen_feat_3": 500.67 + } + }, + { + "id": "t_travel_insurance_gen_3", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance (Gen p_ins_a)", + "features": { + "latency_ms": 235.94, + "cost_usd": 55.24, + "availability": 1.0, + "gen_feat_1": 510.78, + "gen_feat_2": 0.49515, + "gen_feat_3": 514.3 + } + }, + { + "id": "t_travel_insurance_gen_4", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance (Gen p_ins_b)", + "features": { + "latency_ms": 239.19, + "cost_usd": 54.65, + "availability": 0.97242, + "gen_feat_1": 493.99, + "gen_feat_2": 0.507973, + "gen_feat_3": 491.39 + } + }, + { + "id": "t_travel_insurance_gen_5", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_a", + "name": "TIS.getInsurance (Gen p_hotel_a)", + "features": { + "latency_ms": 237.46, + "cost_usd": 55.4, + "availability": 1.0, + "gen_feat_1": 502.98, + "gen_feat_2": 0.490074, + "gen_feat_3": 504.05 + } + }, + { + "id": "t_travel_insurance_gen_6", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_b", + "name": "TIS.getInsurance (Gen p_hotel_b)", + "features": { + "latency_ms": 246.8, + "cost_usd": 55.95, + "availability": 0.997177, + "gen_feat_1": 498.91, + "gen_feat_2": 0.494214, + "gen_feat_3": 502.98 + } + }, + { + "id": "t_travel_insurance_gen_7", + "task_id": "t_travel_insurance", + "provider_id": "p_car_a", + "name": "TIS.getInsurance (Gen p_car_a)", + "features": { + "latency_ms": 246.54, + "cost_usd": 54.9, + "availability": 0.99944, + "gen_feat_1": 492.97, + "gen_feat_2": 0.512985, + "gen_feat_3": 497.1 + } + }, + { + "id": "t_travel_insurance_gen_8", + "task_id": "t_travel_insurance", + "provider_id": "p_car_b", + "name": "TIS.getInsurance (Gen p_car_b)", + "features": { + "latency_ms": 245.14, + "cost_usd": 53.91, + "availability": 1.0, + "gen_feat_1": 507.6, + "gen_feat_2": 0.491973, + "gen_feat_3": 489.42 + } + }, + { + "id": "t_accommodation_booking_gen_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_1", + "name": "ABS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 417.7, + "cost_usd": 957.65, + "availability": 1.0, + "gen_feat_1": 491.17, + "gen_feat_2": 0.487995, + "gen_feat_3": 496.04 + } + }, + { + "id": "t_accommodation_booking_gen_3", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_2", + "name": "ABS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 435.3, + "cost_usd": 943.55, + "availability": 0.98734, + "gen_feat_1": 490.66, + "gen_feat_2": 0.512804, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_accommodation_booking_gen_4", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_3", + "name": "ABS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 424.85, + "cost_usd": 946.36, + "availability": 0.983088, + "gen_feat_1": 490.8, + "gen_feat_2": 0.498715, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_accommodation_booking_gen_5", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_4", + "name": "ABS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 437.83, + "cost_usd": 931.98, + "availability": 0.989306, + "gen_feat_1": 486.79, + "gen_feat_2": 0.511194, + "gen_feat_3": 509.55 + } + }, + { + "id": "t_accommodation_booking_gen_6", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_5", + "name": "ABS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 441.94, + "cost_usd": 938.72, + "availability": 1.0, + "gen_feat_1": 500.85, + "gen_feat_2": 0.494949, + "gen_feat_3": 494.14 + } + }, + { + "id": "t_accommodation_booking_gen_7", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_a", + "name": "ABS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 438.16, + "cost_usd": 938.79, + "availability": 1.0, + "gen_feat_1": 485.27, + "gen_feat_2": 0.498913, + "gen_feat_3": 487.12 + } + }, + { + "id": "t_accommodation_booking_gen_8", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_b", + "name": "ABS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 418.07, + "cost_usd": 922.82, + "availability": 1.0, + "gen_feat_1": 497.81, + "gen_feat_2": 0.502515, + "gen_feat_3": 509.16 + } + }, + { + "id": "t_car_rental_booking_gen_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_a", + "name": "CRS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 312.13, + "cost_usd": 261.53, + "availability": 1.0, + "gen_feat_1": 512.64, + "gen_feat_2": 0.496089, + "gen_feat_3": 504.19 + } + }, + { + "id": "t_car_rental_booking_gen_3", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_b", + "name": "CRS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 313.91, + "cost_usd": 257.49, + "availability": 0.98681, + "gen_feat_1": 512.87, + "gen_feat_2": 0.505241, + "gen_feat_3": 507.29 + } + }, + { + "id": "t_car_rental_booking_gen_4", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_a", + "name": "CRS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 302.5, + "cost_usd": 253.26, + "availability": 0.988174, + "gen_feat_1": 486.1, + "gen_feat_2": 0.485054, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_car_rental_booking_gen_5", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_b", + "name": "CRS.booking (Gen p_int_air_b)", + "features": { + "latency_ms": 318.31, + "cost_usd": 266.75, + "availability": 0.978032, + "gen_feat_1": 497.95, + "gen_feat_2": 0.49628, + "gen_feat_3": 508.32 + } + }, + { + "id": "t_car_rental_booking_gen_6", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_a", + "name": "CRS.booking (Gen p_ins_a)", + "features": { + "latency_ms": 315.37, + "cost_usd": 257.45, + "availability": 0.991843, + "gen_feat_1": 510.59, + "gen_feat_2": 0.501464, + "gen_feat_3": 495.6 + } + }, + { + "id": "t_car_rental_booking_gen_7", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_b", + "name": "CRS.booking (Gen p_ins_b)", + "features": { + "latency_ms": 311.72, + "cost_usd": 255.51, + "availability": 0.984838, + "gen_feat_1": 498.99, + "gen_feat_2": 0.505672, + "gen_feat_3": 506.54 + } + }, + { + "id": "t_car_rental_booking_gen_8", + "task_id": "t_car_rental_booking", + "provider_id": "p_hotel_a", + "name": "CRS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 306.59, + "cost_usd": 258.27, + "availability": 1.0, + "gen_feat_1": 512.19, + "gen_feat_2": 0.506375, + "gen_feat_3": 513.91 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_parallel", + "kind": "AND", + "children": [ + { + "id": "n_as", + "kind": "TASK", + "task_id": "t_attractions_search" + }, + { + "id": "n_booking_flow", + "kind": "SEQ", + "children": [ + { + "id": "n_flight_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.6, + "child": { + "id": "n_dfb", + "kind": "TASK", + "task_id": "t_flight_booking_domestic" + } + }, + { + "p": 0.4, + "child": { + "id": "n_intl_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_ifb", + "kind": "TASK", + "task_id": "t_flight_booking_international" + }, + { + "id": "n_ti", + "kind": "TASK", + "task_id": "t_travel_insurance" + } + ] + } + } + ] + }, + { + "id": "n_ab", + "kind": "TASK", + "task_id": "t_accommodation_booking" + } + ] + } + ] + }, + { + "id": "n_car_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.3, + "child": { + "id": "n_cr", + "kind": "TASK", + "task_id": "t_car_rental_booking" + } + }, + { + "p": 0.7, + "child": { + "id": "n_no_car", + "kind": "ELEMENT", + "description": "Skip car rental (represents the near(...) branch)" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MULTI", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1" + ], + "weights": { + "availability": 0.34, + "cost_usd": 0.33, + "gen_feat_1": 0.33 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1301.98, + "hard": true + }, + { + "id": "gen_c_local_t_accommodation_booking_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_accommodation_booking" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 927.58, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_attractions_search" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_car_rental_booking" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_multi_soft.json b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_multi_soft.json new file mode 100644 index 0000000..874d46e --- /dev/null +++ b/experimentation/instances/benatallah2002-selfserv-travel-solution-cts-itas_multi_soft.json @@ -0,0 +1,1272 @@ +{ + "metadata": { + "id": "benatallah2002-selfserv-travel-solution-cts-itas_multi_soft", + "name": "Travel Solution (Benatallah et al. 2002) [multi, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from the SELF-SERV running example (CTS and ITAS statecharts). QoS values and branch probabilities are illustrative because the paper does not provide numeric QoS.", + "paper": { + "title": "Declarative Compositionand Peer-to-PeerProvisioning of Dynamic WebServices", + "authors": "B. Benatallah et al.", + "year": 2002, + "doi": "10.5555/876875.878987" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Total price charged to customer", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "availability", + "name": "Probability the service invocation succeeds", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_attractions_a", + "name": "AttractionsSearch Provider A" + }, + { + "id": "p_attractions_b", + "name": "AttractionsSearch Provider B" + }, + { + "id": "p_dom_air_a", + "name": "Domestic Airline A" + }, + { + "id": "p_dom_air_b", + "name": "Domestic Airline B" + }, + { + "id": "p_int_air_a", + "name": "International Airline A" + }, + { + "id": "p_int_air_b", + "name": "International Airline B" + }, + { + "id": "p_ins_a", + "name": "Travel Insurance Co. A" + }, + { + "id": "p_ins_b", + "name": "Travel Insurance Co. B" + }, + { + "id": "p_hotel_a", + "name": "Accommodation Provider A" + }, + { + "id": "p_hotel_b", + "name": "Accommodation Provider B" + }, + { + "id": "p_car_a", + "name": "Car Rental Provider A" + }, + { + "id": "p_car_b", + "name": "Car Rental Provider B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_attractions_search", + "name": "Attractions Search (ASS.getAttractions)" + }, + { + "id": "t_flight_booking_domestic", + "name": "Domestic Flight Booking (DFBS.booking)" + }, + { + "id": "t_flight_booking_international", + "name": "International Flight Booking (IFBS.booking)" + }, + { + "id": "t_travel_insurance", + "name": "Travel Insurance (TIS.getInsurance)" + }, + { + "id": "t_accommodation_booking", + "name": "Accommodation Booking (ABS.booking)" + }, + { + "id": "t_car_rental_booking", + "name": "Car Rental Booking (CRS.booking)" + } + ], + "candidates": [ + { + "id": "svc_ass_1", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_a", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 180, + "cost_usd": 0, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ass_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions", + "features": { + "latency_ms": 120, + "cost_usd": 5, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_a", + "name": "DFBS.booking", + "features": { + "latency_ms": 650, + "cost_usd": 420, + "availability": 0.985, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_dfbs_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_dom_air_b", + "name": "DFBS.booking", + "features": { + "latency_ms": 520, + "cost_usd": 460, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking", + "features": { + "latency_ms": 780, + "cost_usd": 820, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_ifbs_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_b", + "name": "IFBS.booking", + "features": { + "latency_ms": 610, + "cost_usd": 900, + "availability": 0.988, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_1", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 240, + "cost_usd": 55, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_tis_2", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance", + "features": { + "latency_ms": 190, + "cost_usd": 70, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_a", + "name": "ABS.booking", + "features": { + "latency_ms": 430, + "cost_usd": 950, + "availability": 0.992, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_abs_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_hotel_b", + "name": "ABS.booking", + "features": { + "latency_ms": 350, + "cost_usd": 1100, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_a", + "name": "CRS.booking", + "features": { + "latency_ms": 310, + "cost_usd": 260, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "svc_crs_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_car_b", + "name": "CRS.booking", + "features": { + "latency_ms": 260, + "cost_usd": 320, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_attractions_search_gen_1", + "task_id": "t_attractions_search", + "provider_id": "p_gen_shared", + "name": "ASS.getAttractions (Gen Shared)", + "features": { + "latency_ms": 180.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.57, + "gen_feat_2": 0.493935, + "gen_feat_3": 485.71 + } + }, + { + "id": "t_flight_booking_domestic_gen_1", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_shared", + "name": "DFBS.booking (Gen Shared)", + "features": { + "latency_ms": 647.32, + "cost_usd": 411.46, + "availability": 0.979506, + "gen_feat_1": 505.68, + "gen_feat_2": 0.506905, + "gen_feat_3": 510.18 + } + }, + { + "id": "t_flight_booking_international_gen_1", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_shared", + "name": "IFBS.booking (Gen Shared)", + "features": { + "latency_ms": 759.62, + "cost_usd": 814.07, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.503149, + "gen_feat_3": 501.18 + } + }, + { + "id": "t_travel_insurance_gen_1", + "task_id": "t_travel_insurance", + "provider_id": "p_gen_shared", + "name": "TIS.getInsurance (Gen Shared)", + "features": { + "latency_ms": 234.01, + "cost_usd": 55.73, + "availability": 0.994473, + "gen_feat_1": 505.2, + "gen_feat_2": 0.498515, + "gen_feat_3": 487.21 + } + }, + { + "id": "t_accommodation_booking_gen_1", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_shared", + "name": "ABS.booking (Gen Shared)", + "features": { + "latency_ms": 423.14, + "cost_usd": 927.58, + "availability": 0.985309, + "gen_feat_1": 494.62, + "gen_feat_2": 0.504056, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_car_rental_booking_gen_1", + "task_id": "t_car_rental_booking", + "provider_id": "p_gen_shared", + "name": "CRS.booking (Gen Shared)", + "features": { + "latency_ms": 303.36, + "cost_usd": 252.45, + "availability": 0.962251, + "gen_feat_1": 502.73, + "gen_feat_2": 0.492905, + "gen_feat_3": 511.21 + } + }, + { + "id": "t_attractions_search_gen_2", + "task_id": "t_attractions_search", + "provider_id": "p_attractions_b", + "name": "ASS.getAttractions (Gen p_attractions_b)", + "features": { + "latency_ms": 183.9, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.11, + "gen_feat_2": 0.507033, + "gen_feat_3": 506.35 + } + }, + { + "id": "t_attractions_search_gen_3", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_a", + "name": "ASS.getAttractions (Gen p_dom_air_a)", + "features": { + "latency_ms": 184.86, + "cost_usd": 0.0, + "availability": 0.973261, + "gen_feat_1": 512.0, + "gen_feat_2": 0.499623, + "gen_feat_3": 508.68 + } + }, + { + "id": "t_attractions_search_gen_4", + "task_id": "t_attractions_search", + "provider_id": "p_dom_air_b", + "name": "ASS.getAttractions (Gen p_dom_air_b)", + "features": { + "latency_ms": 177.98, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.8, + "gen_feat_2": 0.492691, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_attractions_search_gen_5", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_a", + "name": "ASS.getAttractions (Gen p_int_air_a)", + "features": { + "latency_ms": 180.31, + "cost_usd": 0.0, + "availability": 0.975329, + "gen_feat_1": 511.15, + "gen_feat_2": 0.485867, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_attractions_search_gen_6", + "task_id": "t_attractions_search", + "provider_id": "p_int_air_b", + "name": "ASS.getAttractions (Gen p_int_air_b)", + "features": { + "latency_ms": 178.35, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 491.67, + "gen_feat_2": 0.511467, + "gen_feat_3": 505.28 + } + }, + { + "id": "t_attractions_search_gen_7", + "task_id": "t_attractions_search", + "provider_id": "p_ins_a", + "name": "ASS.getAttractions (Gen p_ins_a)", + "features": { + "latency_ms": 183.13, + "cost_usd": 0.0, + "availability": 0.982652, + "gen_feat_1": 486.89, + "gen_feat_2": 0.493076, + "gen_feat_3": 489.66 + } + }, + { + "id": "t_attractions_search_gen_8", + "task_id": "t_attractions_search", + "provider_id": "p_ins_b", + "name": "ASS.getAttractions (Gen p_ins_b)", + "features": { + "latency_ms": 176.67, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 509.91, + "gen_feat_2": 0.510797, + "gen_feat_3": 494.78 + } + }, + { + "id": "t_flight_booking_domestic_gen_2", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_a", + "name": "DFBS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 631.95, + "cost_usd": 420.96, + "availability": 0.993293, + "gen_feat_1": 509.36, + "gen_feat_2": 0.48832, + "gen_feat_3": 493.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_3", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_hotel_b", + "name": "DFBS.booking (Gen p_hotel_b)", + "features": { + "latency_ms": 657.0, + "cost_usd": 410.51, + "availability": 1.0, + "gen_feat_1": 512.88, + "gen_feat_2": 0.494914, + "gen_feat_3": 493.16 + } + }, + { + "id": "t_flight_booking_domestic_gen_4", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_a", + "name": "DFBS.booking (Gen p_car_a)", + "features": { + "latency_ms": 662.74, + "cost_usd": 432.29, + "availability": 0.955965, + "gen_feat_1": 500.97, + "gen_feat_2": 0.486536, + "gen_feat_3": 491.54 + } + }, + { + "id": "t_flight_booking_domestic_gen_5", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_car_b", + "name": "DFBS.booking (Gen p_car_b)", + "features": { + "latency_ms": 660.26, + "cost_usd": 422.73, + "availability": 1.0, + "gen_feat_1": 511.72, + "gen_feat_2": 0.496489, + "gen_feat_3": 514.27 + } + }, + { + "id": "t_flight_booking_domestic_gen_6", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_1", + "name": "DFBS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 638.86, + "cost_usd": 413.02, + "availability": 0.985773, + "gen_feat_1": 498.15, + "gen_feat_2": 0.488561, + "gen_feat_3": 503.45 + } + }, + { + "id": "t_flight_booking_domestic_gen_7", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_2", + "name": "DFBS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 641.08, + "cost_usd": 429.65, + "availability": 0.978204, + "gen_feat_1": 506.04, + "gen_feat_2": 0.496573, + "gen_feat_3": 510.36 + } + }, + { + "id": "t_flight_booking_domestic_gen_8", + "task_id": "t_flight_booking_domestic", + "provider_id": "p_gen_3", + "name": "DFBS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 664.71, + "cost_usd": 414.68, + "availability": 0.966781, + "gen_feat_1": 489.74, + "gen_feat_2": 0.487447, + "gen_feat_3": 486.76 + } + }, + { + "id": "t_flight_booking_international_gen_2", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_4", + "name": "IFBS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 802.29, + "cost_usd": 805.78, + "availability": 0.988419, + "gen_feat_1": 509.12, + "gen_feat_2": 0.493932, + "gen_feat_3": 494.56 + } + }, + { + "id": "t_flight_booking_international_gen_3", + "task_id": "t_flight_booking_international", + "provider_id": "p_gen_5", + "name": "IFBS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 785.65, + "cost_usd": 832.67, + "availability": 1.0, + "gen_feat_1": 498.69, + "gen_feat_2": 0.506699, + "gen_feat_3": 486.23 + } + }, + { + "id": "t_flight_booking_international_gen_4", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_a", + "name": "IFBS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 795.93, + "cost_usd": 844.09, + "availability": 0.963688, + "gen_feat_1": 492.63, + "gen_feat_2": 0.50024, + "gen_feat_3": 503.14 + } + }, + { + "id": "t_flight_booking_international_gen_5", + "task_id": "t_flight_booking_international", + "provider_id": "p_attractions_b", + "name": "IFBS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 763.55, + "cost_usd": 806.59, + "availability": 0.973216, + "gen_feat_1": 490.91, + "gen_feat_2": 0.504181, + "gen_feat_3": 493.32 + } + }, + { + "id": "t_flight_booking_international_gen_6", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_a", + "name": "IFBS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 775.31, + "cost_usd": 813.89, + "availability": 1.0, + "gen_feat_1": 514.34, + "gen_feat_2": 0.490809, + "gen_feat_3": 502.88 + } + }, + { + "id": "t_flight_booking_international_gen_7", + "task_id": "t_flight_booking_international", + "provider_id": "p_dom_air_b", + "name": "IFBS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 774.09, + "cost_usd": 796.86, + "availability": 1.0, + "gen_feat_1": 509.97, + "gen_feat_2": 0.50639, + "gen_feat_3": 488.65 + } + }, + { + "id": "t_flight_booking_international_gen_8", + "task_id": "t_flight_booking_international", + "provider_id": "p_int_air_a", + "name": "IFBS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 802.89, + "cost_usd": 832.54, + "availability": 0.995867, + "gen_feat_1": 500.61, + "gen_feat_2": 0.492753, + "gen_feat_3": 489.35 + } + }, + { + "id": "t_travel_insurance_gen_2", + "task_id": "t_travel_insurance", + "provider_id": "p_int_air_b", + "name": "TIS.getInsurance (Gen p_int_air_b)", + "features": { + "latency_ms": 239.89, + "cost_usd": 54.54, + "availability": 0.978354, + "gen_feat_1": 504.59, + "gen_feat_2": 0.502031, + "gen_feat_3": 500.67 + } + }, + { + "id": "t_travel_insurance_gen_3", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_a", + "name": "TIS.getInsurance (Gen p_ins_a)", + "features": { + "latency_ms": 235.94, + "cost_usd": 55.24, + "availability": 1.0, + "gen_feat_1": 510.78, + "gen_feat_2": 0.49515, + "gen_feat_3": 514.3 + } + }, + { + "id": "t_travel_insurance_gen_4", + "task_id": "t_travel_insurance", + "provider_id": "p_ins_b", + "name": "TIS.getInsurance (Gen p_ins_b)", + "features": { + "latency_ms": 239.19, + "cost_usd": 54.65, + "availability": 0.97242, + "gen_feat_1": 493.99, + "gen_feat_2": 0.507973, + "gen_feat_3": 491.39 + } + }, + { + "id": "t_travel_insurance_gen_5", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_a", + "name": "TIS.getInsurance (Gen p_hotel_a)", + "features": { + "latency_ms": 237.46, + "cost_usd": 55.4, + "availability": 1.0, + "gen_feat_1": 502.98, + "gen_feat_2": 0.490074, + "gen_feat_3": 504.05 + } + }, + { + "id": "t_travel_insurance_gen_6", + "task_id": "t_travel_insurance", + "provider_id": "p_hotel_b", + "name": "TIS.getInsurance (Gen p_hotel_b)", + "features": { + "latency_ms": 246.8, + "cost_usd": 55.95, + "availability": 0.997177, + "gen_feat_1": 498.91, + "gen_feat_2": 0.494214, + "gen_feat_3": 502.98 + } + }, + { + "id": "t_travel_insurance_gen_7", + "task_id": "t_travel_insurance", + "provider_id": "p_car_a", + "name": "TIS.getInsurance (Gen p_car_a)", + "features": { + "latency_ms": 246.54, + "cost_usd": 54.9, + "availability": 0.99944, + "gen_feat_1": 492.97, + "gen_feat_2": 0.512985, + "gen_feat_3": 497.1 + } + }, + { + "id": "t_travel_insurance_gen_8", + "task_id": "t_travel_insurance", + "provider_id": "p_car_b", + "name": "TIS.getInsurance (Gen p_car_b)", + "features": { + "latency_ms": 245.14, + "cost_usd": 53.91, + "availability": 1.0, + "gen_feat_1": 507.6, + "gen_feat_2": 0.491973, + "gen_feat_3": 489.42 + } + }, + { + "id": "t_accommodation_booking_gen_2", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_1", + "name": "ABS.booking (Gen p_gen_1)", + "features": { + "latency_ms": 417.7, + "cost_usd": 957.65, + "availability": 1.0, + "gen_feat_1": 491.17, + "gen_feat_2": 0.487995, + "gen_feat_3": 496.04 + } + }, + { + "id": "t_accommodation_booking_gen_3", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_2", + "name": "ABS.booking (Gen p_gen_2)", + "features": { + "latency_ms": 435.3, + "cost_usd": 943.55, + "availability": 0.98734, + "gen_feat_1": 490.66, + "gen_feat_2": 0.512804, + "gen_feat_3": 508.59 + } + }, + { + "id": "t_accommodation_booking_gen_4", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_3", + "name": "ABS.booking (Gen p_gen_3)", + "features": { + "latency_ms": 424.85, + "cost_usd": 946.36, + "availability": 0.983088, + "gen_feat_1": 490.8, + "gen_feat_2": 0.498715, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_accommodation_booking_gen_5", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_4", + "name": "ABS.booking (Gen p_gen_4)", + "features": { + "latency_ms": 437.83, + "cost_usd": 931.98, + "availability": 0.989306, + "gen_feat_1": 486.79, + "gen_feat_2": 0.511194, + "gen_feat_3": 509.55 + } + }, + { + "id": "t_accommodation_booking_gen_6", + "task_id": "t_accommodation_booking", + "provider_id": "p_gen_5", + "name": "ABS.booking (Gen p_gen_5)", + "features": { + "latency_ms": 441.94, + "cost_usd": 938.72, + "availability": 1.0, + "gen_feat_1": 500.85, + "gen_feat_2": 0.494949, + "gen_feat_3": 494.14 + } + }, + { + "id": "t_accommodation_booking_gen_7", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_a", + "name": "ABS.booking (Gen p_attractions_a)", + "features": { + "latency_ms": 438.16, + "cost_usd": 938.79, + "availability": 1.0, + "gen_feat_1": 485.27, + "gen_feat_2": 0.498913, + "gen_feat_3": 487.12 + } + }, + { + "id": "t_accommodation_booking_gen_8", + "task_id": "t_accommodation_booking", + "provider_id": "p_attractions_b", + "name": "ABS.booking (Gen p_attractions_b)", + "features": { + "latency_ms": 418.07, + "cost_usd": 922.82, + "availability": 1.0, + "gen_feat_1": 497.81, + "gen_feat_2": 0.502515, + "gen_feat_3": 509.16 + } + }, + { + "id": "t_car_rental_booking_gen_2", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_a", + "name": "CRS.booking (Gen p_dom_air_a)", + "features": { + "latency_ms": 312.13, + "cost_usd": 261.53, + "availability": 1.0, + "gen_feat_1": 512.64, + "gen_feat_2": 0.496089, + "gen_feat_3": 504.19 + } + }, + { + "id": "t_car_rental_booking_gen_3", + "task_id": "t_car_rental_booking", + "provider_id": "p_dom_air_b", + "name": "CRS.booking (Gen p_dom_air_b)", + "features": { + "latency_ms": 313.91, + "cost_usd": 257.49, + "availability": 0.98681, + "gen_feat_1": 512.87, + "gen_feat_2": 0.505241, + "gen_feat_3": 507.29 + } + }, + { + "id": "t_car_rental_booking_gen_4", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_a", + "name": "CRS.booking (Gen p_int_air_a)", + "features": { + "latency_ms": 302.5, + "cost_usd": 253.26, + "availability": 0.988174, + "gen_feat_1": 486.1, + "gen_feat_2": 0.485054, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_car_rental_booking_gen_5", + "task_id": "t_car_rental_booking", + "provider_id": "p_int_air_b", + "name": "CRS.booking (Gen p_int_air_b)", + "features": { + "latency_ms": 318.31, + "cost_usd": 266.75, + "availability": 0.978032, + "gen_feat_1": 497.95, + "gen_feat_2": 0.49628, + "gen_feat_3": 508.32 + } + }, + { + "id": "t_car_rental_booking_gen_6", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_a", + "name": "CRS.booking (Gen p_ins_a)", + "features": { + "latency_ms": 315.37, + "cost_usd": 257.45, + "availability": 0.991843, + "gen_feat_1": 510.59, + "gen_feat_2": 0.501464, + "gen_feat_3": 495.6 + } + }, + { + "id": "t_car_rental_booking_gen_7", + "task_id": "t_car_rental_booking", + "provider_id": "p_ins_b", + "name": "CRS.booking (Gen p_ins_b)", + "features": { + "latency_ms": 311.72, + "cost_usd": 255.51, + "availability": 0.984838, + "gen_feat_1": 498.99, + "gen_feat_2": 0.505672, + "gen_feat_3": 506.54 + } + }, + { + "id": "t_car_rental_booking_gen_8", + "task_id": "t_car_rental_booking", + "provider_id": "p_hotel_a", + "name": "CRS.booking (Gen p_hotel_a)", + "features": { + "latency_ms": 306.59, + "cost_usd": 258.27, + "availability": 1.0, + "gen_feat_1": 512.19, + "gen_feat_2": 0.506375, + "gen_feat_3": 513.91 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_parallel", + "kind": "AND", + "children": [ + { + "id": "n_as", + "kind": "TASK", + "task_id": "t_attractions_search" + }, + { + "id": "n_booking_flow", + "kind": "SEQ", + "children": [ + { + "id": "n_flight_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.6, + "child": { + "id": "n_dfb", + "kind": "TASK", + "task_id": "t_flight_booking_domestic" + } + }, + { + "p": 0.4, + "child": { + "id": "n_intl_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_ifb", + "kind": "TASK", + "task_id": "t_flight_booking_international" + }, + { + "id": "n_ti", + "kind": "TASK", + "task_id": "t_travel_insurance" + } + ] + } + } + ] + }, + { + "id": "n_ab", + "kind": "TASK", + "task_id": "t_accommodation_booking" + } + ] + } + ] + }, + { + "id": "n_car_choice", + "kind": "XOR", + "branches": [ + { + "p": 0.3, + "child": { + "id": "n_cr", + "kind": "TASK", + "task_id": "t_car_rental_booking" + } + }, + { + "p": 0.7, + "child": { + "id": "n_no_car", + "kind": "ELEMENT", + "description": "Skip car rental (represents the near(...) branch)" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MULTI", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1" + ], + "weights": { + "availability": 0.34, + "cost_usd": 0.33, + "gen_feat_1": 0.33 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1301.98, + "hard": false + }, + { + "id": "gen_c_local_t_accommodation_booking_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_accommodation_booking" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 927.58, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_attractions_search" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_accommodation_booking", + "t_car_rental_booking" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/bultan2003-warehouse-example_many_hard.json b/experimentation/instances/bultan2003-warehouse-example_many_hard.json new file mode 100644 index 0000000..e397c2b --- /dev/null +++ b/experimentation/instances/bultan2003-warehouse-example_many_hard.json @@ -0,0 +1,995 @@ +{ + "metadata": { + "id": "bultan2003-warehouse-example_many_hard", + "name": "Warehouse Composition example (Bultan et al. 2003) [many, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from Example 2.1 and Example 3.1 (store-bank-warehouse) in Bultan et al., WWW'03.", + "paper": { + "title": "Conversation Specification: A New Approach to Design and Analysis of E-Service Composition", + "authors": "T. Bultan et al.", + "year": 2003, + "doi": "10.1145/775152.775210" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_store", + "name": "Store" + }, + { + "id": "p_bank", + "name": "Bank" + }, + { + "id": "p_wh1", + "name": "Warehouse1" + }, + { + "id": "p_wh2", + "name": "Warehouse2" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_authorize", + "name": "Send authorize (store→bank)" + }, + { + "id": "t_ok", + "name": "Send ok (bank→store)" + }, + { + "id": "t_order1", + "name": "Send order1 (store→warehouse1)" + }, + { + "id": "t_receipt1", + "name": "Send receipt1 (warehouse1→store)" + }, + { + "id": "t_bill1", + "name": "Send bill1 (warehouse1→bank)" + }, + { + "id": "t_payment1", + "name": "Send payment1 (bank→warehouse1)" + }, + { + "id": "t_order2", + "name": "Send order2 (store→warehouse2)" + }, + { + "id": "t_receipt2", + "name": "Send receipt2 (warehouse2→store)" + }, + { + "id": "t_bill2", + "name": "Send bill2 (warehouse2→bank)" + }, + { + "id": "t_payment2", + "name": "Send payment2 (bank→warehouse2)" + } + ], + "candidates": [ + { + "id": "c_authorize_store_v1", + "task_id": "t_authorize", + "provider_id": "p_store", + "name": "authorize", + "features": { + "latency_ms": 55, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_ok_bank_v1", + "task_id": "t_ok", + "provider_id": "p_bank", + "name": "ok", + "features": { + "latency_ms": 45, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order1_store_v1", + "task_id": "t_order1", + "provider_id": "p_store", + "name": "order1", + "features": { + "latency_ms": 65, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt1_wh1_v1", + "task_id": "t_receipt1", + "provider_id": "p_wh1", + "name": "receipt1", + "features": { + "latency_ms": 80, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill1_wh1_v1", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1", + "features": { + "latency_ms": 75, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment1_bank_v1", + "task_id": "t_payment1", + "provider_id": "p_bank", + "name": "payment1", + "features": { + "latency_ms": 90, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order2_store_v1", + "task_id": "t_order2", + "provider_id": "p_store", + "name": "order2", + "features": { + "latency_ms": 70, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt2_wh2_v1", + "task_id": "t_receipt2", + "provider_id": "p_wh2", + "name": "receipt2", + "features": { + "latency_ms": 85, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill2_wh2_v1", + "task_id": "t_bill2", + "provider_id": "p_wh2", + "name": "bill2", + "features": { + "latency_ms": 78, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment2_bank_v1", + "task_id": "t_payment2", + "provider_id": "p_bank", + "name": "payment2", + "features": { + "latency_ms": 95, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_authorize_gen_1", + "task_id": "t_authorize", + "provider_id": "p_gen_shared", + "name": "authorize (Gen Shared)", + "features": { + "latency_ms": 56.03, + "cost_usd": 0.01, + "availability": 0.9942, + "gen_feat_1": 506.18, + "gen_feat_2": 0.499392, + "gen_feat_3": 514.16 + } + }, + { + "id": "t_ok_gen_1", + "task_id": "t_ok", + "provider_id": "p_gen_shared", + "name": "ok (Gen Shared)", + "features": { + "latency_ms": 45.04, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 498.62, + "gen_feat_2": 0.512982, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_order1_gen_1", + "task_id": "t_order1", + "provider_id": "p_gen_shared", + "name": "order1 (Gen Shared)", + "features": { + "latency_ms": 65.77, + "cost_usd": 0.02, + "availability": 0.969077, + "gen_feat_1": 495.0, + "gen_feat_2": 0.514614, + "gen_feat_3": 491.26 + } + }, + { + "id": "t_receipt1_gen_1", + "task_id": "t_receipt1", + "provider_id": "p_gen_shared", + "name": "receipt1 (Gen Shared)", + "features": { + "latency_ms": 78.06, + "cost_usd": 0.02, + "availability": 0.967727, + "gen_feat_1": 500.39, + "gen_feat_2": 0.485136, + "gen_feat_3": 489.78 + } + }, + { + "id": "t_bill1_gen_1", + "task_id": "t_bill1", + "provider_id": "p_gen_shared", + "name": "bill1 (Gen Shared)", + "features": { + "latency_ms": 74.23, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 499.46, + "gen_feat_2": 0.510726, + "gen_feat_3": 507.43 + } + }, + { + "id": "t_payment1_gen_1", + "task_id": "t_payment1", + "provider_id": "p_gen_shared", + "name": "payment1 (Gen Shared)", + "features": { + "latency_ms": 92.58, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 485.22, + "gen_feat_2": 0.502923, + "gen_feat_3": 500.11 + } + }, + { + "id": "t_order2_gen_1", + "task_id": "t_order2", + "provider_id": "p_gen_shared", + "name": "order2 (Gen Shared)", + "features": { + "latency_ms": 69.52, + "cost_usd": 0.02, + "availability": 0.98773, + "gen_feat_1": 498.95, + "gen_feat_2": 0.488362, + "gen_feat_3": 485.48 + } + }, + { + "id": "t_receipt2_gen_1", + "task_id": "t_receipt2", + "provider_id": "p_gen_shared", + "name": "receipt2 (Gen Shared)", + "features": { + "latency_ms": 82.92, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 494.35, + "gen_feat_2": 0.50285, + "gen_feat_3": 507.12 + } + }, + { + "id": "t_bill2_gen_1", + "task_id": "t_bill2", + "provider_id": "p_gen_shared", + "name": "bill2 (Gen Shared)", + "features": { + "latency_ms": 79.01, + "cost_usd": 0.01, + "availability": 0.984644, + "gen_feat_1": 488.32, + "gen_feat_2": 0.499763, + "gen_feat_3": 489.55 + } + }, + { + "id": "t_payment2_gen_1", + "task_id": "t_payment2", + "provider_id": "p_gen_shared", + "name": "payment2 (Gen Shared)", + "features": { + "latency_ms": 92.24, + "cost_usd": 0.03, + "availability": 0.973888, + "gen_feat_1": 499.15, + "gen_feat_2": 0.505463, + "gen_feat_3": 506.65 + } + }, + { + "id": "t_authorize_gen_2", + "task_id": "t_authorize", + "provider_id": "p_wh1", + "name": "authorize (Gen p_wh1)", + "features": { + "latency_ms": 55.42, + "cost_usd": 0.01, + "availability": 0.991822, + "gen_feat_1": 506.11, + "gen_feat_2": 0.506997, + "gen_feat_3": 513.39 + } + }, + { + "id": "t_authorize_gen_3", + "task_id": "t_authorize", + "provider_id": "p_wh2", + "name": "authorize (Gen p_wh2)", + "features": { + "latency_ms": 56.53, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.13, + "gen_feat_2": 0.51125, + "gen_feat_3": 514.21 + } + }, + { + "id": "t_ok_gen_2", + "task_id": "t_ok", + "provider_id": "p_gen_1", + "name": "ok (Gen p_gen_1)", + "features": { + "latency_ms": 46.32, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 489.76, + "gen_feat_2": 0.491295, + "gen_feat_3": 499.11 + } + }, + { + "id": "t_ok_gen_3", + "task_id": "t_ok", + "provider_id": "p_gen_2", + "name": "ok (Gen p_gen_2)", + "features": { + "latency_ms": 44.18, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.78, + "gen_feat_2": 0.505694, + "gen_feat_3": 512.51 + } + }, + { + "id": "t_order1_gen_2", + "task_id": "t_order1", + "provider_id": "p_gen_3", + "name": "order1 (Gen p_gen_3)", + "features": { + "latency_ms": 65.65, + "cost_usd": 0.02, + "availability": 0.97648, + "gen_feat_1": 487.32, + "gen_feat_2": 0.507472, + "gen_feat_3": 497.45 + } + }, + { + "id": "t_order1_gen_3", + "task_id": "t_order1", + "provider_id": "p_gen_4", + "name": "order1 (Gen p_gen_4)", + "features": { + "latency_ms": 64.28, + "cost_usd": 0.02, + "availability": 0.972736, + "gen_feat_1": 486.2, + "gen_feat_2": 0.503633, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_receipt1_gen_2", + "task_id": "t_receipt1", + "provider_id": "p_gen_5", + "name": "receipt1 (Gen p_gen_5)", + "features": { + "latency_ms": 77.78, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.08, + "gen_feat_2": 0.510897, + "gen_feat_3": 486.77 + } + }, + { + "id": "t_receipt1_gen_3", + "task_id": "t_receipt1", + "provider_id": "p_store", + "name": "receipt1 (Gen p_store)", + "features": { + "latency_ms": 80.11, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 508.14, + "gen_feat_2": 0.486315, + "gen_feat_3": 489.94 + } + }, + { + "id": "t_bill1_gen_2", + "task_id": "t_bill1", + "provider_id": "p_bank", + "name": "bill1 (Gen p_bank)", + "features": { + "latency_ms": 77.07, + "cost_usd": 0.02, + "availability": 0.989736, + "gen_feat_1": 511.49, + "gen_feat_2": 0.492918, + "gen_feat_3": 514.68 + } + }, + { + "id": "t_bill1_gen_3", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1 (Gen p_wh1)", + "features": { + "latency_ms": 75.44, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 510.22, + "gen_feat_2": 0.514368, + "gen_feat_3": 505.69 + } + }, + { + "id": "t_payment1_gen_2", + "task_id": "t_payment1", + "provider_id": "p_wh2", + "name": "payment1 (Gen p_wh2)", + "features": { + "latency_ms": 90.7, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 490.92, + "gen_feat_2": 0.486279, + "gen_feat_3": 503.21 + } + }, + { + "id": "t_payment1_gen_3", + "task_id": "t_payment1", + "provider_id": "p_gen_1", + "name": "payment1 (Gen p_gen_1)", + "features": { + "latency_ms": 89.57, + "cost_usd": 0.03, + "availability": 0.990323, + "gen_feat_1": 509.49, + "gen_feat_2": 0.510492, + "gen_feat_3": 494.55 + } + }, + { + "id": "t_order2_gen_2", + "task_id": "t_order2", + "provider_id": "p_gen_2", + "name": "order2 (Gen p_gen_2)", + "features": { + "latency_ms": 71.14, + "cost_usd": 0.02, + "availability": 0.997499, + "gen_feat_1": 498.73, + "gen_feat_2": 0.505964, + "gen_feat_3": 492.35 + } + }, + { + "id": "t_order2_gen_3", + "task_id": "t_order2", + "provider_id": "p_gen_3", + "name": "order2 (Gen p_gen_3)", + "features": { + "latency_ms": 71.51, + "cost_usd": 0.02, + "availability": 0.978474, + "gen_feat_1": 495.91, + "gen_feat_2": 0.487052, + "gen_feat_3": 495.32 + } + }, + { + "id": "t_receipt2_gen_2", + "task_id": "t_receipt2", + "provider_id": "p_gen_4", + "name": "receipt2 (Gen p_gen_4)", + "features": { + "latency_ms": 85.95, + "cost_usd": 0.02, + "availability": 0.996183, + "gen_feat_1": 507.05, + "gen_feat_2": 0.506274, + "gen_feat_3": 489.81 + } + }, + { + "id": "t_receipt2_gen_3", + "task_id": "t_receipt2", + "provider_id": "p_gen_5", + "name": "receipt2 (Gen p_gen_5)", + "features": { + "latency_ms": 83.66, + "cost_usd": 0.01, + "availability": 0.973035, + "gen_feat_1": 491.17, + "gen_feat_2": 0.494194, + "gen_feat_3": 512.8 + } + }, + { + "id": "t_bill2_gen_2", + "task_id": "t_bill2", + "provider_id": "p_store", + "name": "bill2 (Gen p_store)", + "features": { + "latency_ms": 78.39, + "cost_usd": 0.02, + "availability": 0.991877, + "gen_feat_1": 493.57, + "gen_feat_2": 0.506639, + "gen_feat_3": 505.09 + } + }, + { + "id": "t_bill2_gen_3", + "task_id": "t_bill2", + "provider_id": "p_bank", + "name": "bill2 (Gen p_bank)", + "features": { + "latency_ms": 79.37, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 513.41, + "gen_feat_2": 0.503681, + "gen_feat_3": 510.14 + } + }, + { + "id": "t_payment2_gen_2", + "task_id": "t_payment2", + "provider_id": "p_wh1", + "name": "payment2 (Gen p_wh1)", + "features": { + "latency_ms": 93.89, + "cost_usd": 0.03, + "availability": 0.984789, + "gen_feat_1": 505.36, + "gen_feat_2": 0.49305, + "gen_feat_3": 514.13 + } + }, + { + "id": "t_payment2_gen_3", + "task_id": "t_payment2", + "provider_id": "p_wh2", + "name": "payment2 (Gen p_wh2)", + "features": { + "latency_ms": 92.96, + "cost_usd": 0.03, + "availability": 0.981651, + "gen_feat_1": 491.52, + "gen_feat_2": 0.503183, + "gen_feat_3": 492.47 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_authorize", + "kind": "TASK", + "task_id": "t_authorize" + }, + { + "id": "n_ok", + "kind": "TASK", + "task_id": "t_ok" + }, + { + "id": "n_parallel_orders", + "kind": "AND", + "children": [ + { + "id": "n_loop_wh1", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh1_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order1", + "kind": "TASK", + "task_id": "t_order1" + }, + { + "id": "n_wh1_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt1", + "kind": "TASK", + "task_id": "t_receipt1" + }, + { + "id": "n_wh1_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill1", + "kind": "TASK", + "task_id": "t_bill1" + }, + { + "id": "n_payment1", + "kind": "TASK", + "task_id": "t_payment1" + } + ] + } + ] + } + ] + } + }, + { + "id": "n_loop_wh2", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh2_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order2", + "kind": "TASK", + "task_id": "t_order2" + }, + { + "id": "n_wh2_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt2", + "kind": "TASK", + "task_id": "t_receipt2" + }, + { + "id": "n_wh2_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill2", + "kind": "TASK", + "task_id": "t_bill2" + }, + { + "id": "n_payment2", + "kind": "TASK", + "task_id": "t_payment2" + } + ] + } + ] + } + ] + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MANY", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1318.72, + "hard": true + }, + { + "id": "gen_c_local_t_authorize_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_authorize" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.01, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_authorize", + "t_bill1" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_authorize", + "t_payment2" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/bultan2003-warehouse-example_many_soft.json b/experimentation/instances/bultan2003-warehouse-example_many_soft.json new file mode 100644 index 0000000..1b0e66d --- /dev/null +++ b/experimentation/instances/bultan2003-warehouse-example_many_soft.json @@ -0,0 +1,995 @@ +{ + "metadata": { + "id": "bultan2003-warehouse-example_many_soft", + "name": "Warehouse Composition example (Bultan et al. 2003) [many, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from Example 2.1 and Example 3.1 (store-bank-warehouse) in Bultan et al., WWW'03.", + "paper": { + "title": "Conversation Specification: A New Approach to Design and Analysis of E-Service Composition", + "authors": "T. Bultan et al.", + "year": 2003, + "doi": "10.1145/775152.775210" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_store", + "name": "Store" + }, + { + "id": "p_bank", + "name": "Bank" + }, + { + "id": "p_wh1", + "name": "Warehouse1" + }, + { + "id": "p_wh2", + "name": "Warehouse2" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_authorize", + "name": "Send authorize (store→bank)" + }, + { + "id": "t_ok", + "name": "Send ok (bank→store)" + }, + { + "id": "t_order1", + "name": "Send order1 (store→warehouse1)" + }, + { + "id": "t_receipt1", + "name": "Send receipt1 (warehouse1→store)" + }, + { + "id": "t_bill1", + "name": "Send bill1 (warehouse1→bank)" + }, + { + "id": "t_payment1", + "name": "Send payment1 (bank→warehouse1)" + }, + { + "id": "t_order2", + "name": "Send order2 (store→warehouse2)" + }, + { + "id": "t_receipt2", + "name": "Send receipt2 (warehouse2→store)" + }, + { + "id": "t_bill2", + "name": "Send bill2 (warehouse2→bank)" + }, + { + "id": "t_payment2", + "name": "Send payment2 (bank→warehouse2)" + } + ], + "candidates": [ + { + "id": "c_authorize_store_v1", + "task_id": "t_authorize", + "provider_id": "p_store", + "name": "authorize", + "features": { + "latency_ms": 55, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_ok_bank_v1", + "task_id": "t_ok", + "provider_id": "p_bank", + "name": "ok", + "features": { + "latency_ms": 45, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order1_store_v1", + "task_id": "t_order1", + "provider_id": "p_store", + "name": "order1", + "features": { + "latency_ms": 65, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt1_wh1_v1", + "task_id": "t_receipt1", + "provider_id": "p_wh1", + "name": "receipt1", + "features": { + "latency_ms": 80, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill1_wh1_v1", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1", + "features": { + "latency_ms": 75, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment1_bank_v1", + "task_id": "t_payment1", + "provider_id": "p_bank", + "name": "payment1", + "features": { + "latency_ms": 90, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order2_store_v1", + "task_id": "t_order2", + "provider_id": "p_store", + "name": "order2", + "features": { + "latency_ms": 70, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt2_wh2_v1", + "task_id": "t_receipt2", + "provider_id": "p_wh2", + "name": "receipt2", + "features": { + "latency_ms": 85, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill2_wh2_v1", + "task_id": "t_bill2", + "provider_id": "p_wh2", + "name": "bill2", + "features": { + "latency_ms": 78, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment2_bank_v1", + "task_id": "t_payment2", + "provider_id": "p_bank", + "name": "payment2", + "features": { + "latency_ms": 95, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_authorize_gen_1", + "task_id": "t_authorize", + "provider_id": "p_gen_shared", + "name": "authorize (Gen Shared)", + "features": { + "latency_ms": 56.03, + "cost_usd": 0.01, + "availability": 0.9942, + "gen_feat_1": 506.18, + "gen_feat_2": 0.499392, + "gen_feat_3": 514.16 + } + }, + { + "id": "t_ok_gen_1", + "task_id": "t_ok", + "provider_id": "p_gen_shared", + "name": "ok (Gen Shared)", + "features": { + "latency_ms": 45.04, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 498.62, + "gen_feat_2": 0.512982, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_order1_gen_1", + "task_id": "t_order1", + "provider_id": "p_gen_shared", + "name": "order1 (Gen Shared)", + "features": { + "latency_ms": 65.77, + "cost_usd": 0.02, + "availability": 0.969077, + "gen_feat_1": 495.0, + "gen_feat_2": 0.514614, + "gen_feat_3": 491.26 + } + }, + { + "id": "t_receipt1_gen_1", + "task_id": "t_receipt1", + "provider_id": "p_gen_shared", + "name": "receipt1 (Gen Shared)", + "features": { + "latency_ms": 78.06, + "cost_usd": 0.02, + "availability": 0.967727, + "gen_feat_1": 500.39, + "gen_feat_2": 0.485136, + "gen_feat_3": 489.78 + } + }, + { + "id": "t_bill1_gen_1", + "task_id": "t_bill1", + "provider_id": "p_gen_shared", + "name": "bill1 (Gen Shared)", + "features": { + "latency_ms": 74.23, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 499.46, + "gen_feat_2": 0.510726, + "gen_feat_3": 507.43 + } + }, + { + "id": "t_payment1_gen_1", + "task_id": "t_payment1", + "provider_id": "p_gen_shared", + "name": "payment1 (Gen Shared)", + "features": { + "latency_ms": 92.58, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 485.22, + "gen_feat_2": 0.502923, + "gen_feat_3": 500.11 + } + }, + { + "id": "t_order2_gen_1", + "task_id": "t_order2", + "provider_id": "p_gen_shared", + "name": "order2 (Gen Shared)", + "features": { + "latency_ms": 69.52, + "cost_usd": 0.02, + "availability": 0.98773, + "gen_feat_1": 498.95, + "gen_feat_2": 0.488362, + "gen_feat_3": 485.48 + } + }, + { + "id": "t_receipt2_gen_1", + "task_id": "t_receipt2", + "provider_id": "p_gen_shared", + "name": "receipt2 (Gen Shared)", + "features": { + "latency_ms": 82.92, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 494.35, + "gen_feat_2": 0.50285, + "gen_feat_3": 507.12 + } + }, + { + "id": "t_bill2_gen_1", + "task_id": "t_bill2", + "provider_id": "p_gen_shared", + "name": "bill2 (Gen Shared)", + "features": { + "latency_ms": 79.01, + "cost_usd": 0.01, + "availability": 0.984644, + "gen_feat_1": 488.32, + "gen_feat_2": 0.499763, + "gen_feat_3": 489.55 + } + }, + { + "id": "t_payment2_gen_1", + "task_id": "t_payment2", + "provider_id": "p_gen_shared", + "name": "payment2 (Gen Shared)", + "features": { + "latency_ms": 92.24, + "cost_usd": 0.03, + "availability": 0.973888, + "gen_feat_1": 499.15, + "gen_feat_2": 0.505463, + "gen_feat_3": 506.65 + } + }, + { + "id": "t_authorize_gen_2", + "task_id": "t_authorize", + "provider_id": "p_wh1", + "name": "authorize (Gen p_wh1)", + "features": { + "latency_ms": 55.42, + "cost_usd": 0.01, + "availability": 0.991822, + "gen_feat_1": 506.11, + "gen_feat_2": 0.506997, + "gen_feat_3": 513.39 + } + }, + { + "id": "t_authorize_gen_3", + "task_id": "t_authorize", + "provider_id": "p_wh2", + "name": "authorize (Gen p_wh2)", + "features": { + "latency_ms": 56.53, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.13, + "gen_feat_2": 0.51125, + "gen_feat_3": 514.21 + } + }, + { + "id": "t_ok_gen_2", + "task_id": "t_ok", + "provider_id": "p_gen_1", + "name": "ok (Gen p_gen_1)", + "features": { + "latency_ms": 46.32, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 489.76, + "gen_feat_2": 0.491295, + "gen_feat_3": 499.11 + } + }, + { + "id": "t_ok_gen_3", + "task_id": "t_ok", + "provider_id": "p_gen_2", + "name": "ok (Gen p_gen_2)", + "features": { + "latency_ms": 44.18, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.78, + "gen_feat_2": 0.505694, + "gen_feat_3": 512.51 + } + }, + { + "id": "t_order1_gen_2", + "task_id": "t_order1", + "provider_id": "p_gen_3", + "name": "order1 (Gen p_gen_3)", + "features": { + "latency_ms": 65.65, + "cost_usd": 0.02, + "availability": 0.97648, + "gen_feat_1": 487.32, + "gen_feat_2": 0.507472, + "gen_feat_3": 497.45 + } + }, + { + "id": "t_order1_gen_3", + "task_id": "t_order1", + "provider_id": "p_gen_4", + "name": "order1 (Gen p_gen_4)", + "features": { + "latency_ms": 64.28, + "cost_usd": 0.02, + "availability": 0.972736, + "gen_feat_1": 486.2, + "gen_feat_2": 0.503633, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_receipt1_gen_2", + "task_id": "t_receipt1", + "provider_id": "p_gen_5", + "name": "receipt1 (Gen p_gen_5)", + "features": { + "latency_ms": 77.78, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.08, + "gen_feat_2": 0.510897, + "gen_feat_3": 486.77 + } + }, + { + "id": "t_receipt1_gen_3", + "task_id": "t_receipt1", + "provider_id": "p_store", + "name": "receipt1 (Gen p_store)", + "features": { + "latency_ms": 80.11, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 508.14, + "gen_feat_2": 0.486315, + "gen_feat_3": 489.94 + } + }, + { + "id": "t_bill1_gen_2", + "task_id": "t_bill1", + "provider_id": "p_bank", + "name": "bill1 (Gen p_bank)", + "features": { + "latency_ms": 77.07, + "cost_usd": 0.02, + "availability": 0.989736, + "gen_feat_1": 511.49, + "gen_feat_2": 0.492918, + "gen_feat_3": 514.68 + } + }, + { + "id": "t_bill1_gen_3", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1 (Gen p_wh1)", + "features": { + "latency_ms": 75.44, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 510.22, + "gen_feat_2": 0.514368, + "gen_feat_3": 505.69 + } + }, + { + "id": "t_payment1_gen_2", + "task_id": "t_payment1", + "provider_id": "p_wh2", + "name": "payment1 (Gen p_wh2)", + "features": { + "latency_ms": 90.7, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 490.92, + "gen_feat_2": 0.486279, + "gen_feat_3": 503.21 + } + }, + { + "id": "t_payment1_gen_3", + "task_id": "t_payment1", + "provider_id": "p_gen_1", + "name": "payment1 (Gen p_gen_1)", + "features": { + "latency_ms": 89.57, + "cost_usd": 0.03, + "availability": 0.990323, + "gen_feat_1": 509.49, + "gen_feat_2": 0.510492, + "gen_feat_3": 494.55 + } + }, + { + "id": "t_order2_gen_2", + "task_id": "t_order2", + "provider_id": "p_gen_2", + "name": "order2 (Gen p_gen_2)", + "features": { + "latency_ms": 71.14, + "cost_usd": 0.02, + "availability": 0.997499, + "gen_feat_1": 498.73, + "gen_feat_2": 0.505964, + "gen_feat_3": 492.35 + } + }, + { + "id": "t_order2_gen_3", + "task_id": "t_order2", + "provider_id": "p_gen_3", + "name": "order2 (Gen p_gen_3)", + "features": { + "latency_ms": 71.51, + "cost_usd": 0.02, + "availability": 0.978474, + "gen_feat_1": 495.91, + "gen_feat_2": 0.487052, + "gen_feat_3": 495.32 + } + }, + { + "id": "t_receipt2_gen_2", + "task_id": "t_receipt2", + "provider_id": "p_gen_4", + "name": "receipt2 (Gen p_gen_4)", + "features": { + "latency_ms": 85.95, + "cost_usd": 0.02, + "availability": 0.996183, + "gen_feat_1": 507.05, + "gen_feat_2": 0.506274, + "gen_feat_3": 489.81 + } + }, + { + "id": "t_receipt2_gen_3", + "task_id": "t_receipt2", + "provider_id": "p_gen_5", + "name": "receipt2 (Gen p_gen_5)", + "features": { + "latency_ms": 83.66, + "cost_usd": 0.01, + "availability": 0.973035, + "gen_feat_1": 491.17, + "gen_feat_2": 0.494194, + "gen_feat_3": 512.8 + } + }, + { + "id": "t_bill2_gen_2", + "task_id": "t_bill2", + "provider_id": "p_store", + "name": "bill2 (Gen p_store)", + "features": { + "latency_ms": 78.39, + "cost_usd": 0.02, + "availability": 0.991877, + "gen_feat_1": 493.57, + "gen_feat_2": 0.506639, + "gen_feat_3": 505.09 + } + }, + { + "id": "t_bill2_gen_3", + "task_id": "t_bill2", + "provider_id": "p_bank", + "name": "bill2 (Gen p_bank)", + "features": { + "latency_ms": 79.37, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 513.41, + "gen_feat_2": 0.503681, + "gen_feat_3": 510.14 + } + }, + { + "id": "t_payment2_gen_2", + "task_id": "t_payment2", + "provider_id": "p_wh1", + "name": "payment2 (Gen p_wh1)", + "features": { + "latency_ms": 93.89, + "cost_usd": 0.03, + "availability": 0.984789, + "gen_feat_1": 505.36, + "gen_feat_2": 0.49305, + "gen_feat_3": 514.13 + } + }, + { + "id": "t_payment2_gen_3", + "task_id": "t_payment2", + "provider_id": "p_wh2", + "name": "payment2 (Gen p_wh2)", + "features": { + "latency_ms": 92.96, + "cost_usd": 0.03, + "availability": 0.981651, + "gen_feat_1": 491.52, + "gen_feat_2": 0.503183, + "gen_feat_3": 492.47 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_authorize", + "kind": "TASK", + "task_id": "t_authorize" + }, + { + "id": "n_ok", + "kind": "TASK", + "task_id": "t_ok" + }, + { + "id": "n_parallel_orders", + "kind": "AND", + "children": [ + { + "id": "n_loop_wh1", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh1_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order1", + "kind": "TASK", + "task_id": "t_order1" + }, + { + "id": "n_wh1_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt1", + "kind": "TASK", + "task_id": "t_receipt1" + }, + { + "id": "n_wh1_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill1", + "kind": "TASK", + "task_id": "t_bill1" + }, + { + "id": "n_payment1", + "kind": "TASK", + "task_id": "t_payment1" + } + ] + } + ] + } + ] + } + }, + { + "id": "n_loop_wh2", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh2_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order2", + "kind": "TASK", + "task_id": "t_order2" + }, + { + "id": "n_wh2_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt2", + "kind": "TASK", + "task_id": "t_receipt2" + }, + { + "id": "n_wh2_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill2", + "kind": "TASK", + "task_id": "t_bill2" + }, + { + "id": "n_payment2", + "kind": "TASK", + "task_id": "t_payment2" + } + ] + } + ] + } + ] + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MANY", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1318.72, + "hard": false + }, + { + "id": "gen_c_local_t_authorize_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_authorize" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.01, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_authorize", + "t_bill1" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_authorize", + "t_payment2" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/bultan2003-warehouse-example_mono_one_hard.json b/experimentation/instances/bultan2003-warehouse-example_mono_one_hard.json new file mode 100644 index 0000000..e6726a8 --- /dev/null +++ b/experimentation/instances/bultan2003-warehouse-example_mono_one_hard.json @@ -0,0 +1,985 @@ +{ + "metadata": { + "id": "bultan2003-warehouse-example_mono_one_hard", + "name": "Warehouse Composition example (Bultan et al. 2003) [mono_one, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from Example 2.1 and Example 3.1 (store-bank-warehouse) in Bultan et al., WWW'03.", + "paper": { + "title": "Conversation Specification: A New Approach to Design and Analysis of E-Service Composition", + "authors": "T. Bultan et al.", + "year": 2003, + "doi": "10.1145/775152.775210" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_store", + "name": "Store" + }, + { + "id": "p_bank", + "name": "Bank" + }, + { + "id": "p_wh1", + "name": "Warehouse1" + }, + { + "id": "p_wh2", + "name": "Warehouse2" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_authorize", + "name": "Send authorize (store→bank)" + }, + { + "id": "t_ok", + "name": "Send ok (bank→store)" + }, + { + "id": "t_order1", + "name": "Send order1 (store→warehouse1)" + }, + { + "id": "t_receipt1", + "name": "Send receipt1 (warehouse1→store)" + }, + { + "id": "t_bill1", + "name": "Send bill1 (warehouse1→bank)" + }, + { + "id": "t_payment1", + "name": "Send payment1 (bank→warehouse1)" + }, + { + "id": "t_order2", + "name": "Send order2 (store→warehouse2)" + }, + { + "id": "t_receipt2", + "name": "Send receipt2 (warehouse2→store)" + }, + { + "id": "t_bill2", + "name": "Send bill2 (warehouse2→bank)" + }, + { + "id": "t_payment2", + "name": "Send payment2 (bank→warehouse2)" + } + ], + "candidates": [ + { + "id": "c_authorize_store_v1", + "task_id": "t_authorize", + "provider_id": "p_store", + "name": "authorize", + "features": { + "latency_ms": 55, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_ok_bank_v1", + "task_id": "t_ok", + "provider_id": "p_bank", + "name": "ok", + "features": { + "latency_ms": 45, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order1_store_v1", + "task_id": "t_order1", + "provider_id": "p_store", + "name": "order1", + "features": { + "latency_ms": 65, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt1_wh1_v1", + "task_id": "t_receipt1", + "provider_id": "p_wh1", + "name": "receipt1", + "features": { + "latency_ms": 80, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill1_wh1_v1", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1", + "features": { + "latency_ms": 75, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment1_bank_v1", + "task_id": "t_payment1", + "provider_id": "p_bank", + "name": "payment1", + "features": { + "latency_ms": 90, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order2_store_v1", + "task_id": "t_order2", + "provider_id": "p_store", + "name": "order2", + "features": { + "latency_ms": 70, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt2_wh2_v1", + "task_id": "t_receipt2", + "provider_id": "p_wh2", + "name": "receipt2", + "features": { + "latency_ms": 85, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill2_wh2_v1", + "task_id": "t_bill2", + "provider_id": "p_wh2", + "name": "bill2", + "features": { + "latency_ms": 78, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment2_bank_v1", + "task_id": "t_payment2", + "provider_id": "p_bank", + "name": "payment2", + "features": { + "latency_ms": 95, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_authorize_gen_1", + "task_id": "t_authorize", + "provider_id": "p_gen_shared", + "name": "authorize (Gen Shared)", + "features": { + "latency_ms": 56.03, + "cost_usd": 0.01, + "availability": 0.9942, + "gen_feat_1": 506.18, + "gen_feat_2": 0.499392, + "gen_feat_3": 514.16 + } + }, + { + "id": "t_ok_gen_1", + "task_id": "t_ok", + "provider_id": "p_gen_shared", + "name": "ok (Gen Shared)", + "features": { + "latency_ms": 45.04, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 498.62, + "gen_feat_2": 0.512982, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_order1_gen_1", + "task_id": "t_order1", + "provider_id": "p_gen_shared", + "name": "order1 (Gen Shared)", + "features": { + "latency_ms": 65.77, + "cost_usd": 0.02, + "availability": 0.969077, + "gen_feat_1": 495.0, + "gen_feat_2": 0.514614, + "gen_feat_3": 491.26 + } + }, + { + "id": "t_receipt1_gen_1", + "task_id": "t_receipt1", + "provider_id": "p_gen_shared", + "name": "receipt1 (Gen Shared)", + "features": { + "latency_ms": 78.06, + "cost_usd": 0.02, + "availability": 0.967727, + "gen_feat_1": 500.39, + "gen_feat_2": 0.485136, + "gen_feat_3": 489.78 + } + }, + { + "id": "t_bill1_gen_1", + "task_id": "t_bill1", + "provider_id": "p_gen_shared", + "name": "bill1 (Gen Shared)", + "features": { + "latency_ms": 74.23, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 499.46, + "gen_feat_2": 0.510726, + "gen_feat_3": 507.43 + } + }, + { + "id": "t_payment1_gen_1", + "task_id": "t_payment1", + "provider_id": "p_gen_shared", + "name": "payment1 (Gen Shared)", + "features": { + "latency_ms": 92.58, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 485.22, + "gen_feat_2": 0.502923, + "gen_feat_3": 500.11 + } + }, + { + "id": "t_order2_gen_1", + "task_id": "t_order2", + "provider_id": "p_gen_shared", + "name": "order2 (Gen Shared)", + "features": { + "latency_ms": 69.52, + "cost_usd": 0.02, + "availability": 0.98773, + "gen_feat_1": 498.95, + "gen_feat_2": 0.488362, + "gen_feat_3": 485.48 + } + }, + { + "id": "t_receipt2_gen_1", + "task_id": "t_receipt2", + "provider_id": "p_gen_shared", + "name": "receipt2 (Gen Shared)", + "features": { + "latency_ms": 82.92, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 494.35, + "gen_feat_2": 0.50285, + "gen_feat_3": 507.12 + } + }, + { + "id": "t_bill2_gen_1", + "task_id": "t_bill2", + "provider_id": "p_gen_shared", + "name": "bill2 (Gen Shared)", + "features": { + "latency_ms": 79.01, + "cost_usd": 0.01, + "availability": 0.984644, + "gen_feat_1": 488.32, + "gen_feat_2": 0.499763, + "gen_feat_3": 489.55 + } + }, + { + "id": "t_payment2_gen_1", + "task_id": "t_payment2", + "provider_id": "p_gen_shared", + "name": "payment2 (Gen Shared)", + "features": { + "latency_ms": 92.24, + "cost_usd": 0.03, + "availability": 0.973888, + "gen_feat_1": 499.15, + "gen_feat_2": 0.505463, + "gen_feat_3": 506.65 + } + }, + { + "id": "t_authorize_gen_2", + "task_id": "t_authorize", + "provider_id": "p_wh1", + "name": "authorize (Gen p_wh1)", + "features": { + "latency_ms": 55.42, + "cost_usd": 0.01, + "availability": 0.991822, + "gen_feat_1": 506.11, + "gen_feat_2": 0.506997, + "gen_feat_3": 513.39 + } + }, + { + "id": "t_authorize_gen_3", + "task_id": "t_authorize", + "provider_id": "p_wh2", + "name": "authorize (Gen p_wh2)", + "features": { + "latency_ms": 56.53, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.13, + "gen_feat_2": 0.51125, + "gen_feat_3": 514.21 + } + }, + { + "id": "t_ok_gen_2", + "task_id": "t_ok", + "provider_id": "p_gen_1", + "name": "ok (Gen p_gen_1)", + "features": { + "latency_ms": 46.32, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 489.76, + "gen_feat_2": 0.491295, + "gen_feat_3": 499.11 + } + }, + { + "id": "t_ok_gen_3", + "task_id": "t_ok", + "provider_id": "p_gen_2", + "name": "ok (Gen p_gen_2)", + "features": { + "latency_ms": 44.18, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.78, + "gen_feat_2": 0.505694, + "gen_feat_3": 512.51 + } + }, + { + "id": "t_order1_gen_2", + "task_id": "t_order1", + "provider_id": "p_gen_3", + "name": "order1 (Gen p_gen_3)", + "features": { + "latency_ms": 65.65, + "cost_usd": 0.02, + "availability": 0.97648, + "gen_feat_1": 487.32, + "gen_feat_2": 0.507472, + "gen_feat_3": 497.45 + } + }, + { + "id": "t_order1_gen_3", + "task_id": "t_order1", + "provider_id": "p_gen_4", + "name": "order1 (Gen p_gen_4)", + "features": { + "latency_ms": 64.28, + "cost_usd": 0.02, + "availability": 0.972736, + "gen_feat_1": 486.2, + "gen_feat_2": 0.503633, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_receipt1_gen_2", + "task_id": "t_receipt1", + "provider_id": "p_gen_5", + "name": "receipt1 (Gen p_gen_5)", + "features": { + "latency_ms": 77.78, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.08, + "gen_feat_2": 0.510897, + "gen_feat_3": 486.77 + } + }, + { + "id": "t_receipt1_gen_3", + "task_id": "t_receipt1", + "provider_id": "p_store", + "name": "receipt1 (Gen p_store)", + "features": { + "latency_ms": 80.11, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 508.14, + "gen_feat_2": 0.486315, + "gen_feat_3": 489.94 + } + }, + { + "id": "t_bill1_gen_2", + "task_id": "t_bill1", + "provider_id": "p_bank", + "name": "bill1 (Gen p_bank)", + "features": { + "latency_ms": 77.07, + "cost_usd": 0.02, + "availability": 0.989736, + "gen_feat_1": 511.49, + "gen_feat_2": 0.492918, + "gen_feat_3": 514.68 + } + }, + { + "id": "t_bill1_gen_3", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1 (Gen p_wh1)", + "features": { + "latency_ms": 75.44, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 510.22, + "gen_feat_2": 0.514368, + "gen_feat_3": 505.69 + } + }, + { + "id": "t_payment1_gen_2", + "task_id": "t_payment1", + "provider_id": "p_wh2", + "name": "payment1 (Gen p_wh2)", + "features": { + "latency_ms": 90.7, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 490.92, + "gen_feat_2": 0.486279, + "gen_feat_3": 503.21 + } + }, + { + "id": "t_payment1_gen_3", + "task_id": "t_payment1", + "provider_id": "p_gen_1", + "name": "payment1 (Gen p_gen_1)", + "features": { + "latency_ms": 89.57, + "cost_usd": 0.03, + "availability": 0.990323, + "gen_feat_1": 509.49, + "gen_feat_2": 0.510492, + "gen_feat_3": 494.55 + } + }, + { + "id": "t_order2_gen_2", + "task_id": "t_order2", + "provider_id": "p_gen_2", + "name": "order2 (Gen p_gen_2)", + "features": { + "latency_ms": 71.14, + "cost_usd": 0.02, + "availability": 0.997499, + "gen_feat_1": 498.73, + "gen_feat_2": 0.505964, + "gen_feat_3": 492.35 + } + }, + { + "id": "t_order2_gen_3", + "task_id": "t_order2", + "provider_id": "p_gen_3", + "name": "order2 (Gen p_gen_3)", + "features": { + "latency_ms": 71.51, + "cost_usd": 0.02, + "availability": 0.978474, + "gen_feat_1": 495.91, + "gen_feat_2": 0.487052, + "gen_feat_3": 495.32 + } + }, + { + "id": "t_receipt2_gen_2", + "task_id": "t_receipt2", + "provider_id": "p_gen_4", + "name": "receipt2 (Gen p_gen_4)", + "features": { + "latency_ms": 85.95, + "cost_usd": 0.02, + "availability": 0.996183, + "gen_feat_1": 507.05, + "gen_feat_2": 0.506274, + "gen_feat_3": 489.81 + } + }, + { + "id": "t_receipt2_gen_3", + "task_id": "t_receipt2", + "provider_id": "p_gen_5", + "name": "receipt2 (Gen p_gen_5)", + "features": { + "latency_ms": 83.66, + "cost_usd": 0.01, + "availability": 0.973035, + "gen_feat_1": 491.17, + "gen_feat_2": 0.494194, + "gen_feat_3": 512.8 + } + }, + { + "id": "t_bill2_gen_2", + "task_id": "t_bill2", + "provider_id": "p_store", + "name": "bill2 (Gen p_store)", + "features": { + "latency_ms": 78.39, + "cost_usd": 0.02, + "availability": 0.991877, + "gen_feat_1": 493.57, + "gen_feat_2": 0.506639, + "gen_feat_3": 505.09 + } + }, + { + "id": "t_bill2_gen_3", + "task_id": "t_bill2", + "provider_id": "p_bank", + "name": "bill2 (Gen p_bank)", + "features": { + "latency_ms": 79.37, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 513.41, + "gen_feat_2": 0.503681, + "gen_feat_3": 510.14 + } + }, + { + "id": "t_payment2_gen_2", + "task_id": "t_payment2", + "provider_id": "p_wh1", + "name": "payment2 (Gen p_wh1)", + "features": { + "latency_ms": 93.89, + "cost_usd": 0.03, + "availability": 0.984789, + "gen_feat_1": 505.36, + "gen_feat_2": 0.49305, + "gen_feat_3": 514.13 + } + }, + { + "id": "t_payment2_gen_3", + "task_id": "t_payment2", + "provider_id": "p_wh2", + "name": "payment2 (Gen p_wh2)", + "features": { + "latency_ms": 92.96, + "cost_usd": 0.03, + "availability": 0.981651, + "gen_feat_1": 491.52, + "gen_feat_2": 0.503183, + "gen_feat_3": 492.47 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_authorize", + "kind": "TASK", + "task_id": "t_authorize" + }, + { + "id": "n_ok", + "kind": "TASK", + "task_id": "t_ok" + }, + { + "id": "n_parallel_orders", + "kind": "AND", + "children": [ + { + "id": "n_loop_wh1", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh1_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order1", + "kind": "TASK", + "task_id": "t_order1" + }, + { + "id": "n_wh1_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt1", + "kind": "TASK", + "task_id": "t_receipt1" + }, + { + "id": "n_wh1_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill1", + "kind": "TASK", + "task_id": "t_bill1" + }, + { + "id": "n_payment1", + "kind": "TASK", + "task_id": "t_payment1" + } + ] + } + ] + } + ] + } + }, + { + "id": "n_loop_wh2", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh2_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order2", + "kind": "TASK", + "task_id": "t_order2" + }, + { + "id": "n_wh2_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt2", + "kind": "TASK", + "task_id": "t_receipt2" + }, + { + "id": "n_wh2_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill2", + "kind": "TASK", + "task_id": "t_bill2" + }, + { + "id": "n_payment2", + "kind": "TASK", + "task_id": "t_payment2" + } + ] + } + ] + } + ] + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "availability" + ], + "weights": { + "availability": 1.0 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1318.72, + "hard": true + }, + { + "id": "gen_c_local_t_authorize_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_authorize" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.01, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_authorize", + "t_bill1" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_authorize", + "t_payment2" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/bultan2003-warehouse-example_mono_one_soft.json b/experimentation/instances/bultan2003-warehouse-example_mono_one_soft.json new file mode 100644 index 0000000..8792b94 --- /dev/null +++ b/experimentation/instances/bultan2003-warehouse-example_mono_one_soft.json @@ -0,0 +1,985 @@ +{ + "metadata": { + "id": "bultan2003-warehouse-example_mono_one_soft", + "name": "Warehouse Composition example (Bultan et al. 2003) [mono_one, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from Example 2.1 and Example 3.1 (store-bank-warehouse) in Bultan et al., WWW'03.", + "paper": { + "title": "Conversation Specification: A New Approach to Design and Analysis of E-Service Composition", + "authors": "T. Bultan et al.", + "year": 2003, + "doi": "10.1145/775152.775210" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_store", + "name": "Store" + }, + { + "id": "p_bank", + "name": "Bank" + }, + { + "id": "p_wh1", + "name": "Warehouse1" + }, + { + "id": "p_wh2", + "name": "Warehouse2" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_authorize", + "name": "Send authorize (store→bank)" + }, + { + "id": "t_ok", + "name": "Send ok (bank→store)" + }, + { + "id": "t_order1", + "name": "Send order1 (store→warehouse1)" + }, + { + "id": "t_receipt1", + "name": "Send receipt1 (warehouse1→store)" + }, + { + "id": "t_bill1", + "name": "Send bill1 (warehouse1→bank)" + }, + { + "id": "t_payment1", + "name": "Send payment1 (bank→warehouse1)" + }, + { + "id": "t_order2", + "name": "Send order2 (store→warehouse2)" + }, + { + "id": "t_receipt2", + "name": "Send receipt2 (warehouse2→store)" + }, + { + "id": "t_bill2", + "name": "Send bill2 (warehouse2→bank)" + }, + { + "id": "t_payment2", + "name": "Send payment2 (bank→warehouse2)" + } + ], + "candidates": [ + { + "id": "c_authorize_store_v1", + "task_id": "t_authorize", + "provider_id": "p_store", + "name": "authorize", + "features": { + "latency_ms": 55, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_ok_bank_v1", + "task_id": "t_ok", + "provider_id": "p_bank", + "name": "ok", + "features": { + "latency_ms": 45, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order1_store_v1", + "task_id": "t_order1", + "provider_id": "p_store", + "name": "order1", + "features": { + "latency_ms": 65, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt1_wh1_v1", + "task_id": "t_receipt1", + "provider_id": "p_wh1", + "name": "receipt1", + "features": { + "latency_ms": 80, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill1_wh1_v1", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1", + "features": { + "latency_ms": 75, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment1_bank_v1", + "task_id": "t_payment1", + "provider_id": "p_bank", + "name": "payment1", + "features": { + "latency_ms": 90, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order2_store_v1", + "task_id": "t_order2", + "provider_id": "p_store", + "name": "order2", + "features": { + "latency_ms": 70, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt2_wh2_v1", + "task_id": "t_receipt2", + "provider_id": "p_wh2", + "name": "receipt2", + "features": { + "latency_ms": 85, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill2_wh2_v1", + "task_id": "t_bill2", + "provider_id": "p_wh2", + "name": "bill2", + "features": { + "latency_ms": 78, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment2_bank_v1", + "task_id": "t_payment2", + "provider_id": "p_bank", + "name": "payment2", + "features": { + "latency_ms": 95, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_authorize_gen_1", + "task_id": "t_authorize", + "provider_id": "p_gen_shared", + "name": "authorize (Gen Shared)", + "features": { + "latency_ms": 56.03, + "cost_usd": 0.01, + "availability": 0.9942, + "gen_feat_1": 506.18, + "gen_feat_2": 0.499392, + "gen_feat_3": 514.16 + } + }, + { + "id": "t_ok_gen_1", + "task_id": "t_ok", + "provider_id": "p_gen_shared", + "name": "ok (Gen Shared)", + "features": { + "latency_ms": 45.04, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 498.62, + "gen_feat_2": 0.512982, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_order1_gen_1", + "task_id": "t_order1", + "provider_id": "p_gen_shared", + "name": "order1 (Gen Shared)", + "features": { + "latency_ms": 65.77, + "cost_usd": 0.02, + "availability": 0.969077, + "gen_feat_1": 495.0, + "gen_feat_2": 0.514614, + "gen_feat_3": 491.26 + } + }, + { + "id": "t_receipt1_gen_1", + "task_id": "t_receipt1", + "provider_id": "p_gen_shared", + "name": "receipt1 (Gen Shared)", + "features": { + "latency_ms": 78.06, + "cost_usd": 0.02, + "availability": 0.967727, + "gen_feat_1": 500.39, + "gen_feat_2": 0.485136, + "gen_feat_3": 489.78 + } + }, + { + "id": "t_bill1_gen_1", + "task_id": "t_bill1", + "provider_id": "p_gen_shared", + "name": "bill1 (Gen Shared)", + "features": { + "latency_ms": 74.23, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 499.46, + "gen_feat_2": 0.510726, + "gen_feat_3": 507.43 + } + }, + { + "id": "t_payment1_gen_1", + "task_id": "t_payment1", + "provider_id": "p_gen_shared", + "name": "payment1 (Gen Shared)", + "features": { + "latency_ms": 92.58, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 485.22, + "gen_feat_2": 0.502923, + "gen_feat_3": 500.11 + } + }, + { + "id": "t_order2_gen_1", + "task_id": "t_order2", + "provider_id": "p_gen_shared", + "name": "order2 (Gen Shared)", + "features": { + "latency_ms": 69.52, + "cost_usd": 0.02, + "availability": 0.98773, + "gen_feat_1": 498.95, + "gen_feat_2": 0.488362, + "gen_feat_3": 485.48 + } + }, + { + "id": "t_receipt2_gen_1", + "task_id": "t_receipt2", + "provider_id": "p_gen_shared", + "name": "receipt2 (Gen Shared)", + "features": { + "latency_ms": 82.92, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 494.35, + "gen_feat_2": 0.50285, + "gen_feat_3": 507.12 + } + }, + { + "id": "t_bill2_gen_1", + "task_id": "t_bill2", + "provider_id": "p_gen_shared", + "name": "bill2 (Gen Shared)", + "features": { + "latency_ms": 79.01, + "cost_usd": 0.01, + "availability": 0.984644, + "gen_feat_1": 488.32, + "gen_feat_2": 0.499763, + "gen_feat_3": 489.55 + } + }, + { + "id": "t_payment2_gen_1", + "task_id": "t_payment2", + "provider_id": "p_gen_shared", + "name": "payment2 (Gen Shared)", + "features": { + "latency_ms": 92.24, + "cost_usd": 0.03, + "availability": 0.973888, + "gen_feat_1": 499.15, + "gen_feat_2": 0.505463, + "gen_feat_3": 506.65 + } + }, + { + "id": "t_authorize_gen_2", + "task_id": "t_authorize", + "provider_id": "p_wh1", + "name": "authorize (Gen p_wh1)", + "features": { + "latency_ms": 55.42, + "cost_usd": 0.01, + "availability": 0.991822, + "gen_feat_1": 506.11, + "gen_feat_2": 0.506997, + "gen_feat_3": 513.39 + } + }, + { + "id": "t_authorize_gen_3", + "task_id": "t_authorize", + "provider_id": "p_wh2", + "name": "authorize (Gen p_wh2)", + "features": { + "latency_ms": 56.53, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.13, + "gen_feat_2": 0.51125, + "gen_feat_3": 514.21 + } + }, + { + "id": "t_ok_gen_2", + "task_id": "t_ok", + "provider_id": "p_gen_1", + "name": "ok (Gen p_gen_1)", + "features": { + "latency_ms": 46.32, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 489.76, + "gen_feat_2": 0.491295, + "gen_feat_3": 499.11 + } + }, + { + "id": "t_ok_gen_3", + "task_id": "t_ok", + "provider_id": "p_gen_2", + "name": "ok (Gen p_gen_2)", + "features": { + "latency_ms": 44.18, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.78, + "gen_feat_2": 0.505694, + "gen_feat_3": 512.51 + } + }, + { + "id": "t_order1_gen_2", + "task_id": "t_order1", + "provider_id": "p_gen_3", + "name": "order1 (Gen p_gen_3)", + "features": { + "latency_ms": 65.65, + "cost_usd": 0.02, + "availability": 0.97648, + "gen_feat_1": 487.32, + "gen_feat_2": 0.507472, + "gen_feat_3": 497.45 + } + }, + { + "id": "t_order1_gen_3", + "task_id": "t_order1", + "provider_id": "p_gen_4", + "name": "order1 (Gen p_gen_4)", + "features": { + "latency_ms": 64.28, + "cost_usd": 0.02, + "availability": 0.972736, + "gen_feat_1": 486.2, + "gen_feat_2": 0.503633, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_receipt1_gen_2", + "task_id": "t_receipt1", + "provider_id": "p_gen_5", + "name": "receipt1 (Gen p_gen_5)", + "features": { + "latency_ms": 77.78, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.08, + "gen_feat_2": 0.510897, + "gen_feat_3": 486.77 + } + }, + { + "id": "t_receipt1_gen_3", + "task_id": "t_receipt1", + "provider_id": "p_store", + "name": "receipt1 (Gen p_store)", + "features": { + "latency_ms": 80.11, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 508.14, + "gen_feat_2": 0.486315, + "gen_feat_3": 489.94 + } + }, + { + "id": "t_bill1_gen_2", + "task_id": "t_bill1", + "provider_id": "p_bank", + "name": "bill1 (Gen p_bank)", + "features": { + "latency_ms": 77.07, + "cost_usd": 0.02, + "availability": 0.989736, + "gen_feat_1": 511.49, + "gen_feat_2": 0.492918, + "gen_feat_3": 514.68 + } + }, + { + "id": "t_bill1_gen_3", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1 (Gen p_wh1)", + "features": { + "latency_ms": 75.44, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 510.22, + "gen_feat_2": 0.514368, + "gen_feat_3": 505.69 + } + }, + { + "id": "t_payment1_gen_2", + "task_id": "t_payment1", + "provider_id": "p_wh2", + "name": "payment1 (Gen p_wh2)", + "features": { + "latency_ms": 90.7, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 490.92, + "gen_feat_2": 0.486279, + "gen_feat_3": 503.21 + } + }, + { + "id": "t_payment1_gen_3", + "task_id": "t_payment1", + "provider_id": "p_gen_1", + "name": "payment1 (Gen p_gen_1)", + "features": { + "latency_ms": 89.57, + "cost_usd": 0.03, + "availability": 0.990323, + "gen_feat_1": 509.49, + "gen_feat_2": 0.510492, + "gen_feat_3": 494.55 + } + }, + { + "id": "t_order2_gen_2", + "task_id": "t_order2", + "provider_id": "p_gen_2", + "name": "order2 (Gen p_gen_2)", + "features": { + "latency_ms": 71.14, + "cost_usd": 0.02, + "availability": 0.997499, + "gen_feat_1": 498.73, + "gen_feat_2": 0.505964, + "gen_feat_3": 492.35 + } + }, + { + "id": "t_order2_gen_3", + "task_id": "t_order2", + "provider_id": "p_gen_3", + "name": "order2 (Gen p_gen_3)", + "features": { + "latency_ms": 71.51, + "cost_usd": 0.02, + "availability": 0.978474, + "gen_feat_1": 495.91, + "gen_feat_2": 0.487052, + "gen_feat_3": 495.32 + } + }, + { + "id": "t_receipt2_gen_2", + "task_id": "t_receipt2", + "provider_id": "p_gen_4", + "name": "receipt2 (Gen p_gen_4)", + "features": { + "latency_ms": 85.95, + "cost_usd": 0.02, + "availability": 0.996183, + "gen_feat_1": 507.05, + "gen_feat_2": 0.506274, + "gen_feat_3": 489.81 + } + }, + { + "id": "t_receipt2_gen_3", + "task_id": "t_receipt2", + "provider_id": "p_gen_5", + "name": "receipt2 (Gen p_gen_5)", + "features": { + "latency_ms": 83.66, + "cost_usd": 0.01, + "availability": 0.973035, + "gen_feat_1": 491.17, + "gen_feat_2": 0.494194, + "gen_feat_3": 512.8 + } + }, + { + "id": "t_bill2_gen_2", + "task_id": "t_bill2", + "provider_id": "p_store", + "name": "bill2 (Gen p_store)", + "features": { + "latency_ms": 78.39, + "cost_usd": 0.02, + "availability": 0.991877, + "gen_feat_1": 493.57, + "gen_feat_2": 0.506639, + "gen_feat_3": 505.09 + } + }, + { + "id": "t_bill2_gen_3", + "task_id": "t_bill2", + "provider_id": "p_bank", + "name": "bill2 (Gen p_bank)", + "features": { + "latency_ms": 79.37, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 513.41, + "gen_feat_2": 0.503681, + "gen_feat_3": 510.14 + } + }, + { + "id": "t_payment2_gen_2", + "task_id": "t_payment2", + "provider_id": "p_wh1", + "name": "payment2 (Gen p_wh1)", + "features": { + "latency_ms": 93.89, + "cost_usd": 0.03, + "availability": 0.984789, + "gen_feat_1": 505.36, + "gen_feat_2": 0.49305, + "gen_feat_3": 514.13 + } + }, + { + "id": "t_payment2_gen_3", + "task_id": "t_payment2", + "provider_id": "p_wh2", + "name": "payment2 (Gen p_wh2)", + "features": { + "latency_ms": 92.96, + "cost_usd": 0.03, + "availability": 0.981651, + "gen_feat_1": 491.52, + "gen_feat_2": 0.503183, + "gen_feat_3": 492.47 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_authorize", + "kind": "TASK", + "task_id": "t_authorize" + }, + { + "id": "n_ok", + "kind": "TASK", + "task_id": "t_ok" + }, + { + "id": "n_parallel_orders", + "kind": "AND", + "children": [ + { + "id": "n_loop_wh1", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh1_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order1", + "kind": "TASK", + "task_id": "t_order1" + }, + { + "id": "n_wh1_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt1", + "kind": "TASK", + "task_id": "t_receipt1" + }, + { + "id": "n_wh1_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill1", + "kind": "TASK", + "task_id": "t_bill1" + }, + { + "id": "n_payment1", + "kind": "TASK", + "task_id": "t_payment1" + } + ] + } + ] + } + ] + } + }, + { + "id": "n_loop_wh2", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh2_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order2", + "kind": "TASK", + "task_id": "t_order2" + }, + { + "id": "n_wh2_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt2", + "kind": "TASK", + "task_id": "t_receipt2" + }, + { + "id": "n_wh2_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill2", + "kind": "TASK", + "task_id": "t_bill2" + }, + { + "id": "n_payment2", + "kind": "TASK", + "task_id": "t_payment2" + } + ] + } + ] + } + ] + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "availability" + ], + "weights": { + "availability": 1.0 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1318.72, + "hard": false + }, + { + "id": "gen_c_local_t_authorize_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_authorize" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.01, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_authorize", + "t_bill1" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_authorize", + "t_payment2" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/bultan2003-warehouse-example_mono_utility_hard.json b/experimentation/instances/bultan2003-warehouse-example_mono_utility_hard.json new file mode 100644 index 0000000..0509b44 --- /dev/null +++ b/experimentation/instances/bultan2003-warehouse-example_mono_utility_hard.json @@ -0,0 +1,995 @@ +{ + "metadata": { + "id": "bultan2003-warehouse-example_mono_utility_hard", + "name": "Warehouse Composition example (Bultan et al. 2003) [mono_utility, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from Example 2.1 and Example 3.1 (store-bank-warehouse) in Bultan et al., WWW'03.", + "paper": { + "title": "Conversation Specification: A New Approach to Design and Analysis of E-Service Composition", + "authors": "T. Bultan et al.", + "year": 2003, + "doi": "10.1145/775152.775210" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_store", + "name": "Store" + }, + { + "id": "p_bank", + "name": "Bank" + }, + { + "id": "p_wh1", + "name": "Warehouse1" + }, + { + "id": "p_wh2", + "name": "Warehouse2" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_authorize", + "name": "Send authorize (store→bank)" + }, + { + "id": "t_ok", + "name": "Send ok (bank→store)" + }, + { + "id": "t_order1", + "name": "Send order1 (store→warehouse1)" + }, + { + "id": "t_receipt1", + "name": "Send receipt1 (warehouse1→store)" + }, + { + "id": "t_bill1", + "name": "Send bill1 (warehouse1→bank)" + }, + { + "id": "t_payment1", + "name": "Send payment1 (bank→warehouse1)" + }, + { + "id": "t_order2", + "name": "Send order2 (store→warehouse2)" + }, + { + "id": "t_receipt2", + "name": "Send receipt2 (warehouse2→store)" + }, + { + "id": "t_bill2", + "name": "Send bill2 (warehouse2→bank)" + }, + { + "id": "t_payment2", + "name": "Send payment2 (bank→warehouse2)" + } + ], + "candidates": [ + { + "id": "c_authorize_store_v1", + "task_id": "t_authorize", + "provider_id": "p_store", + "name": "authorize", + "features": { + "latency_ms": 55, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_ok_bank_v1", + "task_id": "t_ok", + "provider_id": "p_bank", + "name": "ok", + "features": { + "latency_ms": 45, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order1_store_v1", + "task_id": "t_order1", + "provider_id": "p_store", + "name": "order1", + "features": { + "latency_ms": 65, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt1_wh1_v1", + "task_id": "t_receipt1", + "provider_id": "p_wh1", + "name": "receipt1", + "features": { + "latency_ms": 80, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill1_wh1_v1", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1", + "features": { + "latency_ms": 75, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment1_bank_v1", + "task_id": "t_payment1", + "provider_id": "p_bank", + "name": "payment1", + "features": { + "latency_ms": 90, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order2_store_v1", + "task_id": "t_order2", + "provider_id": "p_store", + "name": "order2", + "features": { + "latency_ms": 70, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt2_wh2_v1", + "task_id": "t_receipt2", + "provider_id": "p_wh2", + "name": "receipt2", + "features": { + "latency_ms": 85, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill2_wh2_v1", + "task_id": "t_bill2", + "provider_id": "p_wh2", + "name": "bill2", + "features": { + "latency_ms": 78, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment2_bank_v1", + "task_id": "t_payment2", + "provider_id": "p_bank", + "name": "payment2", + "features": { + "latency_ms": 95, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_authorize_gen_1", + "task_id": "t_authorize", + "provider_id": "p_gen_shared", + "name": "authorize (Gen Shared)", + "features": { + "latency_ms": 56.03, + "cost_usd": 0.01, + "availability": 0.9942, + "gen_feat_1": 506.18, + "gen_feat_2": 0.499392, + "gen_feat_3": 514.16 + } + }, + { + "id": "t_ok_gen_1", + "task_id": "t_ok", + "provider_id": "p_gen_shared", + "name": "ok (Gen Shared)", + "features": { + "latency_ms": 45.04, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 498.62, + "gen_feat_2": 0.512982, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_order1_gen_1", + "task_id": "t_order1", + "provider_id": "p_gen_shared", + "name": "order1 (Gen Shared)", + "features": { + "latency_ms": 65.77, + "cost_usd": 0.02, + "availability": 0.969077, + "gen_feat_1": 495.0, + "gen_feat_2": 0.514614, + "gen_feat_3": 491.26 + } + }, + { + "id": "t_receipt1_gen_1", + "task_id": "t_receipt1", + "provider_id": "p_gen_shared", + "name": "receipt1 (Gen Shared)", + "features": { + "latency_ms": 78.06, + "cost_usd": 0.02, + "availability": 0.967727, + "gen_feat_1": 500.39, + "gen_feat_2": 0.485136, + "gen_feat_3": 489.78 + } + }, + { + "id": "t_bill1_gen_1", + "task_id": "t_bill1", + "provider_id": "p_gen_shared", + "name": "bill1 (Gen Shared)", + "features": { + "latency_ms": 74.23, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 499.46, + "gen_feat_2": 0.510726, + "gen_feat_3": 507.43 + } + }, + { + "id": "t_payment1_gen_1", + "task_id": "t_payment1", + "provider_id": "p_gen_shared", + "name": "payment1 (Gen Shared)", + "features": { + "latency_ms": 92.58, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 485.22, + "gen_feat_2": 0.502923, + "gen_feat_3": 500.11 + } + }, + { + "id": "t_order2_gen_1", + "task_id": "t_order2", + "provider_id": "p_gen_shared", + "name": "order2 (Gen Shared)", + "features": { + "latency_ms": 69.52, + "cost_usd": 0.02, + "availability": 0.98773, + "gen_feat_1": 498.95, + "gen_feat_2": 0.488362, + "gen_feat_3": 485.48 + } + }, + { + "id": "t_receipt2_gen_1", + "task_id": "t_receipt2", + "provider_id": "p_gen_shared", + "name": "receipt2 (Gen Shared)", + "features": { + "latency_ms": 82.92, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 494.35, + "gen_feat_2": 0.50285, + "gen_feat_3": 507.12 + } + }, + { + "id": "t_bill2_gen_1", + "task_id": "t_bill2", + "provider_id": "p_gen_shared", + "name": "bill2 (Gen Shared)", + "features": { + "latency_ms": 79.01, + "cost_usd": 0.01, + "availability": 0.984644, + "gen_feat_1": 488.32, + "gen_feat_2": 0.499763, + "gen_feat_3": 489.55 + } + }, + { + "id": "t_payment2_gen_1", + "task_id": "t_payment2", + "provider_id": "p_gen_shared", + "name": "payment2 (Gen Shared)", + "features": { + "latency_ms": 92.24, + "cost_usd": 0.03, + "availability": 0.973888, + "gen_feat_1": 499.15, + "gen_feat_2": 0.505463, + "gen_feat_3": 506.65 + } + }, + { + "id": "t_authorize_gen_2", + "task_id": "t_authorize", + "provider_id": "p_wh1", + "name": "authorize (Gen p_wh1)", + "features": { + "latency_ms": 55.42, + "cost_usd": 0.01, + "availability": 0.991822, + "gen_feat_1": 506.11, + "gen_feat_2": 0.506997, + "gen_feat_3": 513.39 + } + }, + { + "id": "t_authorize_gen_3", + "task_id": "t_authorize", + "provider_id": "p_wh2", + "name": "authorize (Gen p_wh2)", + "features": { + "latency_ms": 56.53, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.13, + "gen_feat_2": 0.51125, + "gen_feat_3": 514.21 + } + }, + { + "id": "t_ok_gen_2", + "task_id": "t_ok", + "provider_id": "p_gen_1", + "name": "ok (Gen p_gen_1)", + "features": { + "latency_ms": 46.32, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 489.76, + "gen_feat_2": 0.491295, + "gen_feat_3": 499.11 + } + }, + { + "id": "t_ok_gen_3", + "task_id": "t_ok", + "provider_id": "p_gen_2", + "name": "ok (Gen p_gen_2)", + "features": { + "latency_ms": 44.18, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.78, + "gen_feat_2": 0.505694, + "gen_feat_3": 512.51 + } + }, + { + "id": "t_order1_gen_2", + "task_id": "t_order1", + "provider_id": "p_gen_3", + "name": "order1 (Gen p_gen_3)", + "features": { + "latency_ms": 65.65, + "cost_usd": 0.02, + "availability": 0.97648, + "gen_feat_1": 487.32, + "gen_feat_2": 0.507472, + "gen_feat_3": 497.45 + } + }, + { + "id": "t_order1_gen_3", + "task_id": "t_order1", + "provider_id": "p_gen_4", + "name": "order1 (Gen p_gen_4)", + "features": { + "latency_ms": 64.28, + "cost_usd": 0.02, + "availability": 0.972736, + "gen_feat_1": 486.2, + "gen_feat_2": 0.503633, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_receipt1_gen_2", + "task_id": "t_receipt1", + "provider_id": "p_gen_5", + "name": "receipt1 (Gen p_gen_5)", + "features": { + "latency_ms": 77.78, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.08, + "gen_feat_2": 0.510897, + "gen_feat_3": 486.77 + } + }, + { + "id": "t_receipt1_gen_3", + "task_id": "t_receipt1", + "provider_id": "p_store", + "name": "receipt1 (Gen p_store)", + "features": { + "latency_ms": 80.11, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 508.14, + "gen_feat_2": 0.486315, + "gen_feat_3": 489.94 + } + }, + { + "id": "t_bill1_gen_2", + "task_id": "t_bill1", + "provider_id": "p_bank", + "name": "bill1 (Gen p_bank)", + "features": { + "latency_ms": 77.07, + "cost_usd": 0.02, + "availability": 0.989736, + "gen_feat_1": 511.49, + "gen_feat_2": 0.492918, + "gen_feat_3": 514.68 + } + }, + { + "id": "t_bill1_gen_3", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1 (Gen p_wh1)", + "features": { + "latency_ms": 75.44, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 510.22, + "gen_feat_2": 0.514368, + "gen_feat_3": 505.69 + } + }, + { + "id": "t_payment1_gen_2", + "task_id": "t_payment1", + "provider_id": "p_wh2", + "name": "payment1 (Gen p_wh2)", + "features": { + "latency_ms": 90.7, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 490.92, + "gen_feat_2": 0.486279, + "gen_feat_3": 503.21 + } + }, + { + "id": "t_payment1_gen_3", + "task_id": "t_payment1", + "provider_id": "p_gen_1", + "name": "payment1 (Gen p_gen_1)", + "features": { + "latency_ms": 89.57, + "cost_usd": 0.03, + "availability": 0.990323, + "gen_feat_1": 509.49, + "gen_feat_2": 0.510492, + "gen_feat_3": 494.55 + } + }, + { + "id": "t_order2_gen_2", + "task_id": "t_order2", + "provider_id": "p_gen_2", + "name": "order2 (Gen p_gen_2)", + "features": { + "latency_ms": 71.14, + "cost_usd": 0.02, + "availability": 0.997499, + "gen_feat_1": 498.73, + "gen_feat_2": 0.505964, + "gen_feat_3": 492.35 + } + }, + { + "id": "t_order2_gen_3", + "task_id": "t_order2", + "provider_id": "p_gen_3", + "name": "order2 (Gen p_gen_3)", + "features": { + "latency_ms": 71.51, + "cost_usd": 0.02, + "availability": 0.978474, + "gen_feat_1": 495.91, + "gen_feat_2": 0.487052, + "gen_feat_3": 495.32 + } + }, + { + "id": "t_receipt2_gen_2", + "task_id": "t_receipt2", + "provider_id": "p_gen_4", + "name": "receipt2 (Gen p_gen_4)", + "features": { + "latency_ms": 85.95, + "cost_usd": 0.02, + "availability": 0.996183, + "gen_feat_1": 507.05, + "gen_feat_2": 0.506274, + "gen_feat_3": 489.81 + } + }, + { + "id": "t_receipt2_gen_3", + "task_id": "t_receipt2", + "provider_id": "p_gen_5", + "name": "receipt2 (Gen p_gen_5)", + "features": { + "latency_ms": 83.66, + "cost_usd": 0.01, + "availability": 0.973035, + "gen_feat_1": 491.17, + "gen_feat_2": 0.494194, + "gen_feat_3": 512.8 + } + }, + { + "id": "t_bill2_gen_2", + "task_id": "t_bill2", + "provider_id": "p_store", + "name": "bill2 (Gen p_store)", + "features": { + "latency_ms": 78.39, + "cost_usd": 0.02, + "availability": 0.991877, + "gen_feat_1": 493.57, + "gen_feat_2": 0.506639, + "gen_feat_3": 505.09 + } + }, + { + "id": "t_bill2_gen_3", + "task_id": "t_bill2", + "provider_id": "p_bank", + "name": "bill2 (Gen p_bank)", + "features": { + "latency_ms": 79.37, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 513.41, + "gen_feat_2": 0.503681, + "gen_feat_3": 510.14 + } + }, + { + "id": "t_payment2_gen_2", + "task_id": "t_payment2", + "provider_id": "p_wh1", + "name": "payment2 (Gen p_wh1)", + "features": { + "latency_ms": 93.89, + "cost_usd": 0.03, + "availability": 0.984789, + "gen_feat_1": 505.36, + "gen_feat_2": 0.49305, + "gen_feat_3": 514.13 + } + }, + { + "id": "t_payment2_gen_3", + "task_id": "t_payment2", + "provider_id": "p_wh2", + "name": "payment2 (Gen p_wh2)", + "features": { + "latency_ms": 92.96, + "cost_usd": 0.03, + "availability": 0.981651, + "gen_feat_1": 491.52, + "gen_feat_2": 0.503183, + "gen_feat_3": 492.47 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_authorize", + "kind": "TASK", + "task_id": "t_authorize" + }, + { + "id": "n_ok", + "kind": "TASK", + "task_id": "t_ok" + }, + { + "id": "n_parallel_orders", + "kind": "AND", + "children": [ + { + "id": "n_loop_wh1", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh1_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order1", + "kind": "TASK", + "task_id": "t_order1" + }, + { + "id": "n_wh1_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt1", + "kind": "TASK", + "task_id": "t_receipt1" + }, + { + "id": "n_wh1_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill1", + "kind": "TASK", + "task_id": "t_bill1" + }, + { + "id": "n_payment1", + "kind": "TASK", + "task_id": "t_payment1" + } + ] + } + ] + } + ] + } + }, + { + "id": "n_loop_wh2", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh2_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order2", + "kind": "TASK", + "task_id": "t_order2" + }, + { + "id": "n_wh2_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt2", + "kind": "TASK", + "task_id": "t_receipt2" + }, + { + "id": "n_wh2_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill2", + "kind": "TASK", + "task_id": "t_bill2" + }, + { + "id": "n_payment2", + "kind": "TASK", + "task_id": "t_payment2" + } + ] + } + ] + } + ] + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1318.72, + "hard": true + }, + { + "id": "gen_c_local_t_authorize_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_authorize" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.01, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_authorize", + "t_bill1" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_authorize", + "t_payment2" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/bultan2003-warehouse-example_mono_utility_soft.json b/experimentation/instances/bultan2003-warehouse-example_mono_utility_soft.json new file mode 100644 index 0000000..e505794 --- /dev/null +++ b/experimentation/instances/bultan2003-warehouse-example_mono_utility_soft.json @@ -0,0 +1,995 @@ +{ + "metadata": { + "id": "bultan2003-warehouse-example_mono_utility_soft", + "name": "Warehouse Composition example (Bultan et al. 2003) [mono_utility, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from Example 2.1 and Example 3.1 (store-bank-warehouse) in Bultan et al., WWW'03.", + "paper": { + "title": "Conversation Specification: A New Approach to Design and Analysis of E-Service Composition", + "authors": "T. Bultan et al.", + "year": 2003, + "doi": "10.1145/775152.775210" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_store", + "name": "Store" + }, + { + "id": "p_bank", + "name": "Bank" + }, + { + "id": "p_wh1", + "name": "Warehouse1" + }, + { + "id": "p_wh2", + "name": "Warehouse2" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_authorize", + "name": "Send authorize (store→bank)" + }, + { + "id": "t_ok", + "name": "Send ok (bank→store)" + }, + { + "id": "t_order1", + "name": "Send order1 (store→warehouse1)" + }, + { + "id": "t_receipt1", + "name": "Send receipt1 (warehouse1→store)" + }, + { + "id": "t_bill1", + "name": "Send bill1 (warehouse1→bank)" + }, + { + "id": "t_payment1", + "name": "Send payment1 (bank→warehouse1)" + }, + { + "id": "t_order2", + "name": "Send order2 (store→warehouse2)" + }, + { + "id": "t_receipt2", + "name": "Send receipt2 (warehouse2→store)" + }, + { + "id": "t_bill2", + "name": "Send bill2 (warehouse2→bank)" + }, + { + "id": "t_payment2", + "name": "Send payment2 (bank→warehouse2)" + } + ], + "candidates": [ + { + "id": "c_authorize_store_v1", + "task_id": "t_authorize", + "provider_id": "p_store", + "name": "authorize", + "features": { + "latency_ms": 55, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_ok_bank_v1", + "task_id": "t_ok", + "provider_id": "p_bank", + "name": "ok", + "features": { + "latency_ms": 45, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order1_store_v1", + "task_id": "t_order1", + "provider_id": "p_store", + "name": "order1", + "features": { + "latency_ms": 65, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt1_wh1_v1", + "task_id": "t_receipt1", + "provider_id": "p_wh1", + "name": "receipt1", + "features": { + "latency_ms": 80, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill1_wh1_v1", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1", + "features": { + "latency_ms": 75, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment1_bank_v1", + "task_id": "t_payment1", + "provider_id": "p_bank", + "name": "payment1", + "features": { + "latency_ms": 90, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order2_store_v1", + "task_id": "t_order2", + "provider_id": "p_store", + "name": "order2", + "features": { + "latency_ms": 70, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt2_wh2_v1", + "task_id": "t_receipt2", + "provider_id": "p_wh2", + "name": "receipt2", + "features": { + "latency_ms": 85, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill2_wh2_v1", + "task_id": "t_bill2", + "provider_id": "p_wh2", + "name": "bill2", + "features": { + "latency_ms": 78, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment2_bank_v1", + "task_id": "t_payment2", + "provider_id": "p_bank", + "name": "payment2", + "features": { + "latency_ms": 95, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_authorize_gen_1", + "task_id": "t_authorize", + "provider_id": "p_gen_shared", + "name": "authorize (Gen Shared)", + "features": { + "latency_ms": 56.03, + "cost_usd": 0.01, + "availability": 0.9942, + "gen_feat_1": 506.18, + "gen_feat_2": 0.499392, + "gen_feat_3": 514.16 + } + }, + { + "id": "t_ok_gen_1", + "task_id": "t_ok", + "provider_id": "p_gen_shared", + "name": "ok (Gen Shared)", + "features": { + "latency_ms": 45.04, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 498.62, + "gen_feat_2": 0.512982, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_order1_gen_1", + "task_id": "t_order1", + "provider_id": "p_gen_shared", + "name": "order1 (Gen Shared)", + "features": { + "latency_ms": 65.77, + "cost_usd": 0.02, + "availability": 0.969077, + "gen_feat_1": 495.0, + "gen_feat_2": 0.514614, + "gen_feat_3": 491.26 + } + }, + { + "id": "t_receipt1_gen_1", + "task_id": "t_receipt1", + "provider_id": "p_gen_shared", + "name": "receipt1 (Gen Shared)", + "features": { + "latency_ms": 78.06, + "cost_usd": 0.02, + "availability": 0.967727, + "gen_feat_1": 500.39, + "gen_feat_2": 0.485136, + "gen_feat_3": 489.78 + } + }, + { + "id": "t_bill1_gen_1", + "task_id": "t_bill1", + "provider_id": "p_gen_shared", + "name": "bill1 (Gen Shared)", + "features": { + "latency_ms": 74.23, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 499.46, + "gen_feat_2": 0.510726, + "gen_feat_3": 507.43 + } + }, + { + "id": "t_payment1_gen_1", + "task_id": "t_payment1", + "provider_id": "p_gen_shared", + "name": "payment1 (Gen Shared)", + "features": { + "latency_ms": 92.58, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 485.22, + "gen_feat_2": 0.502923, + "gen_feat_3": 500.11 + } + }, + { + "id": "t_order2_gen_1", + "task_id": "t_order2", + "provider_id": "p_gen_shared", + "name": "order2 (Gen Shared)", + "features": { + "latency_ms": 69.52, + "cost_usd": 0.02, + "availability": 0.98773, + "gen_feat_1": 498.95, + "gen_feat_2": 0.488362, + "gen_feat_3": 485.48 + } + }, + { + "id": "t_receipt2_gen_1", + "task_id": "t_receipt2", + "provider_id": "p_gen_shared", + "name": "receipt2 (Gen Shared)", + "features": { + "latency_ms": 82.92, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 494.35, + "gen_feat_2": 0.50285, + "gen_feat_3": 507.12 + } + }, + { + "id": "t_bill2_gen_1", + "task_id": "t_bill2", + "provider_id": "p_gen_shared", + "name": "bill2 (Gen Shared)", + "features": { + "latency_ms": 79.01, + "cost_usd": 0.01, + "availability": 0.984644, + "gen_feat_1": 488.32, + "gen_feat_2": 0.499763, + "gen_feat_3": 489.55 + } + }, + { + "id": "t_payment2_gen_1", + "task_id": "t_payment2", + "provider_id": "p_gen_shared", + "name": "payment2 (Gen Shared)", + "features": { + "latency_ms": 92.24, + "cost_usd": 0.03, + "availability": 0.973888, + "gen_feat_1": 499.15, + "gen_feat_2": 0.505463, + "gen_feat_3": 506.65 + } + }, + { + "id": "t_authorize_gen_2", + "task_id": "t_authorize", + "provider_id": "p_wh1", + "name": "authorize (Gen p_wh1)", + "features": { + "latency_ms": 55.42, + "cost_usd": 0.01, + "availability": 0.991822, + "gen_feat_1": 506.11, + "gen_feat_2": 0.506997, + "gen_feat_3": 513.39 + } + }, + { + "id": "t_authorize_gen_3", + "task_id": "t_authorize", + "provider_id": "p_wh2", + "name": "authorize (Gen p_wh2)", + "features": { + "latency_ms": 56.53, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.13, + "gen_feat_2": 0.51125, + "gen_feat_3": 514.21 + } + }, + { + "id": "t_ok_gen_2", + "task_id": "t_ok", + "provider_id": "p_gen_1", + "name": "ok (Gen p_gen_1)", + "features": { + "latency_ms": 46.32, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 489.76, + "gen_feat_2": 0.491295, + "gen_feat_3": 499.11 + } + }, + { + "id": "t_ok_gen_3", + "task_id": "t_ok", + "provider_id": "p_gen_2", + "name": "ok (Gen p_gen_2)", + "features": { + "latency_ms": 44.18, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.78, + "gen_feat_2": 0.505694, + "gen_feat_3": 512.51 + } + }, + { + "id": "t_order1_gen_2", + "task_id": "t_order1", + "provider_id": "p_gen_3", + "name": "order1 (Gen p_gen_3)", + "features": { + "latency_ms": 65.65, + "cost_usd": 0.02, + "availability": 0.97648, + "gen_feat_1": 487.32, + "gen_feat_2": 0.507472, + "gen_feat_3": 497.45 + } + }, + { + "id": "t_order1_gen_3", + "task_id": "t_order1", + "provider_id": "p_gen_4", + "name": "order1 (Gen p_gen_4)", + "features": { + "latency_ms": 64.28, + "cost_usd": 0.02, + "availability": 0.972736, + "gen_feat_1": 486.2, + "gen_feat_2": 0.503633, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_receipt1_gen_2", + "task_id": "t_receipt1", + "provider_id": "p_gen_5", + "name": "receipt1 (Gen p_gen_5)", + "features": { + "latency_ms": 77.78, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.08, + "gen_feat_2": 0.510897, + "gen_feat_3": 486.77 + } + }, + { + "id": "t_receipt1_gen_3", + "task_id": "t_receipt1", + "provider_id": "p_store", + "name": "receipt1 (Gen p_store)", + "features": { + "latency_ms": 80.11, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 508.14, + "gen_feat_2": 0.486315, + "gen_feat_3": 489.94 + } + }, + { + "id": "t_bill1_gen_2", + "task_id": "t_bill1", + "provider_id": "p_bank", + "name": "bill1 (Gen p_bank)", + "features": { + "latency_ms": 77.07, + "cost_usd": 0.02, + "availability": 0.989736, + "gen_feat_1": 511.49, + "gen_feat_2": 0.492918, + "gen_feat_3": 514.68 + } + }, + { + "id": "t_bill1_gen_3", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1 (Gen p_wh1)", + "features": { + "latency_ms": 75.44, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 510.22, + "gen_feat_2": 0.514368, + "gen_feat_3": 505.69 + } + }, + { + "id": "t_payment1_gen_2", + "task_id": "t_payment1", + "provider_id": "p_wh2", + "name": "payment1 (Gen p_wh2)", + "features": { + "latency_ms": 90.7, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 490.92, + "gen_feat_2": 0.486279, + "gen_feat_3": 503.21 + } + }, + { + "id": "t_payment1_gen_3", + "task_id": "t_payment1", + "provider_id": "p_gen_1", + "name": "payment1 (Gen p_gen_1)", + "features": { + "latency_ms": 89.57, + "cost_usd": 0.03, + "availability": 0.990323, + "gen_feat_1": 509.49, + "gen_feat_2": 0.510492, + "gen_feat_3": 494.55 + } + }, + { + "id": "t_order2_gen_2", + "task_id": "t_order2", + "provider_id": "p_gen_2", + "name": "order2 (Gen p_gen_2)", + "features": { + "latency_ms": 71.14, + "cost_usd": 0.02, + "availability": 0.997499, + "gen_feat_1": 498.73, + "gen_feat_2": 0.505964, + "gen_feat_3": 492.35 + } + }, + { + "id": "t_order2_gen_3", + "task_id": "t_order2", + "provider_id": "p_gen_3", + "name": "order2 (Gen p_gen_3)", + "features": { + "latency_ms": 71.51, + "cost_usd": 0.02, + "availability": 0.978474, + "gen_feat_1": 495.91, + "gen_feat_2": 0.487052, + "gen_feat_3": 495.32 + } + }, + { + "id": "t_receipt2_gen_2", + "task_id": "t_receipt2", + "provider_id": "p_gen_4", + "name": "receipt2 (Gen p_gen_4)", + "features": { + "latency_ms": 85.95, + "cost_usd": 0.02, + "availability": 0.996183, + "gen_feat_1": 507.05, + "gen_feat_2": 0.506274, + "gen_feat_3": 489.81 + } + }, + { + "id": "t_receipt2_gen_3", + "task_id": "t_receipt2", + "provider_id": "p_gen_5", + "name": "receipt2 (Gen p_gen_5)", + "features": { + "latency_ms": 83.66, + "cost_usd": 0.01, + "availability": 0.973035, + "gen_feat_1": 491.17, + "gen_feat_2": 0.494194, + "gen_feat_3": 512.8 + } + }, + { + "id": "t_bill2_gen_2", + "task_id": "t_bill2", + "provider_id": "p_store", + "name": "bill2 (Gen p_store)", + "features": { + "latency_ms": 78.39, + "cost_usd": 0.02, + "availability": 0.991877, + "gen_feat_1": 493.57, + "gen_feat_2": 0.506639, + "gen_feat_3": 505.09 + } + }, + { + "id": "t_bill2_gen_3", + "task_id": "t_bill2", + "provider_id": "p_bank", + "name": "bill2 (Gen p_bank)", + "features": { + "latency_ms": 79.37, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 513.41, + "gen_feat_2": 0.503681, + "gen_feat_3": 510.14 + } + }, + { + "id": "t_payment2_gen_2", + "task_id": "t_payment2", + "provider_id": "p_wh1", + "name": "payment2 (Gen p_wh1)", + "features": { + "latency_ms": 93.89, + "cost_usd": 0.03, + "availability": 0.984789, + "gen_feat_1": 505.36, + "gen_feat_2": 0.49305, + "gen_feat_3": 514.13 + } + }, + { + "id": "t_payment2_gen_3", + "task_id": "t_payment2", + "provider_id": "p_wh2", + "name": "payment2 (Gen p_wh2)", + "features": { + "latency_ms": 92.96, + "cost_usd": 0.03, + "availability": 0.981651, + "gen_feat_1": 491.52, + "gen_feat_2": 0.503183, + "gen_feat_3": 492.47 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_authorize", + "kind": "TASK", + "task_id": "t_authorize" + }, + { + "id": "n_ok", + "kind": "TASK", + "task_id": "t_ok" + }, + { + "id": "n_parallel_orders", + "kind": "AND", + "children": [ + { + "id": "n_loop_wh1", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh1_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order1", + "kind": "TASK", + "task_id": "t_order1" + }, + { + "id": "n_wh1_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt1", + "kind": "TASK", + "task_id": "t_receipt1" + }, + { + "id": "n_wh1_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill1", + "kind": "TASK", + "task_id": "t_bill1" + }, + { + "id": "n_payment1", + "kind": "TASK", + "task_id": "t_payment1" + } + ] + } + ] + } + ] + } + }, + { + "id": "n_loop_wh2", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh2_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order2", + "kind": "TASK", + "task_id": "t_order2" + }, + { + "id": "n_wh2_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt2", + "kind": "TASK", + "task_id": "t_receipt2" + }, + { + "id": "n_wh2_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill2", + "kind": "TASK", + "task_id": "t_bill2" + }, + { + "id": "n_payment2", + "kind": "TASK", + "task_id": "t_payment2" + } + ] + } + ] + } + ] + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1318.72, + "hard": false + }, + { + "id": "gen_c_local_t_authorize_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_authorize" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.01, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_authorize", + "t_bill1" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_authorize", + "t_payment2" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/bultan2003-warehouse-example_multi_hard.json b/experimentation/instances/bultan2003-warehouse-example_multi_hard.json new file mode 100644 index 0000000..408f87e --- /dev/null +++ b/experimentation/instances/bultan2003-warehouse-example_multi_hard.json @@ -0,0 +1,989 @@ +{ + "metadata": { + "id": "bultan2003-warehouse-example_multi_hard", + "name": "Warehouse Composition example (Bultan et al. 2003) [multi, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from Example 2.1 and Example 3.1 (store-bank-warehouse) in Bultan et al., WWW'03.", + "paper": { + "title": "Conversation Specification: A New Approach to Design and Analysis of E-Service Composition", + "authors": "T. Bultan et al.", + "year": 2003, + "doi": "10.1145/775152.775210" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_store", + "name": "Store" + }, + { + "id": "p_bank", + "name": "Bank" + }, + { + "id": "p_wh1", + "name": "Warehouse1" + }, + { + "id": "p_wh2", + "name": "Warehouse2" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_authorize", + "name": "Send authorize (store→bank)" + }, + { + "id": "t_ok", + "name": "Send ok (bank→store)" + }, + { + "id": "t_order1", + "name": "Send order1 (store→warehouse1)" + }, + { + "id": "t_receipt1", + "name": "Send receipt1 (warehouse1→store)" + }, + { + "id": "t_bill1", + "name": "Send bill1 (warehouse1→bank)" + }, + { + "id": "t_payment1", + "name": "Send payment1 (bank→warehouse1)" + }, + { + "id": "t_order2", + "name": "Send order2 (store→warehouse2)" + }, + { + "id": "t_receipt2", + "name": "Send receipt2 (warehouse2→store)" + }, + { + "id": "t_bill2", + "name": "Send bill2 (warehouse2→bank)" + }, + { + "id": "t_payment2", + "name": "Send payment2 (bank→warehouse2)" + } + ], + "candidates": [ + { + "id": "c_authorize_store_v1", + "task_id": "t_authorize", + "provider_id": "p_store", + "name": "authorize", + "features": { + "latency_ms": 55, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_ok_bank_v1", + "task_id": "t_ok", + "provider_id": "p_bank", + "name": "ok", + "features": { + "latency_ms": 45, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order1_store_v1", + "task_id": "t_order1", + "provider_id": "p_store", + "name": "order1", + "features": { + "latency_ms": 65, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt1_wh1_v1", + "task_id": "t_receipt1", + "provider_id": "p_wh1", + "name": "receipt1", + "features": { + "latency_ms": 80, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill1_wh1_v1", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1", + "features": { + "latency_ms": 75, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment1_bank_v1", + "task_id": "t_payment1", + "provider_id": "p_bank", + "name": "payment1", + "features": { + "latency_ms": 90, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order2_store_v1", + "task_id": "t_order2", + "provider_id": "p_store", + "name": "order2", + "features": { + "latency_ms": 70, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt2_wh2_v1", + "task_id": "t_receipt2", + "provider_id": "p_wh2", + "name": "receipt2", + "features": { + "latency_ms": 85, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill2_wh2_v1", + "task_id": "t_bill2", + "provider_id": "p_wh2", + "name": "bill2", + "features": { + "latency_ms": 78, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment2_bank_v1", + "task_id": "t_payment2", + "provider_id": "p_bank", + "name": "payment2", + "features": { + "latency_ms": 95, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_authorize_gen_1", + "task_id": "t_authorize", + "provider_id": "p_gen_shared", + "name": "authorize (Gen Shared)", + "features": { + "latency_ms": 56.03, + "cost_usd": 0.01, + "availability": 0.9942, + "gen_feat_1": 506.18, + "gen_feat_2": 0.499392, + "gen_feat_3": 514.16 + } + }, + { + "id": "t_ok_gen_1", + "task_id": "t_ok", + "provider_id": "p_gen_shared", + "name": "ok (Gen Shared)", + "features": { + "latency_ms": 45.04, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 498.62, + "gen_feat_2": 0.512982, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_order1_gen_1", + "task_id": "t_order1", + "provider_id": "p_gen_shared", + "name": "order1 (Gen Shared)", + "features": { + "latency_ms": 65.77, + "cost_usd": 0.02, + "availability": 0.969077, + "gen_feat_1": 495.0, + "gen_feat_2": 0.514614, + "gen_feat_3": 491.26 + } + }, + { + "id": "t_receipt1_gen_1", + "task_id": "t_receipt1", + "provider_id": "p_gen_shared", + "name": "receipt1 (Gen Shared)", + "features": { + "latency_ms": 78.06, + "cost_usd": 0.02, + "availability": 0.967727, + "gen_feat_1": 500.39, + "gen_feat_2": 0.485136, + "gen_feat_3": 489.78 + } + }, + { + "id": "t_bill1_gen_1", + "task_id": "t_bill1", + "provider_id": "p_gen_shared", + "name": "bill1 (Gen Shared)", + "features": { + "latency_ms": 74.23, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 499.46, + "gen_feat_2": 0.510726, + "gen_feat_3": 507.43 + } + }, + { + "id": "t_payment1_gen_1", + "task_id": "t_payment1", + "provider_id": "p_gen_shared", + "name": "payment1 (Gen Shared)", + "features": { + "latency_ms": 92.58, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 485.22, + "gen_feat_2": 0.502923, + "gen_feat_3": 500.11 + } + }, + { + "id": "t_order2_gen_1", + "task_id": "t_order2", + "provider_id": "p_gen_shared", + "name": "order2 (Gen Shared)", + "features": { + "latency_ms": 69.52, + "cost_usd": 0.02, + "availability": 0.98773, + "gen_feat_1": 498.95, + "gen_feat_2": 0.488362, + "gen_feat_3": 485.48 + } + }, + { + "id": "t_receipt2_gen_1", + "task_id": "t_receipt2", + "provider_id": "p_gen_shared", + "name": "receipt2 (Gen Shared)", + "features": { + "latency_ms": 82.92, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 494.35, + "gen_feat_2": 0.50285, + "gen_feat_3": 507.12 + } + }, + { + "id": "t_bill2_gen_1", + "task_id": "t_bill2", + "provider_id": "p_gen_shared", + "name": "bill2 (Gen Shared)", + "features": { + "latency_ms": 79.01, + "cost_usd": 0.01, + "availability": 0.984644, + "gen_feat_1": 488.32, + "gen_feat_2": 0.499763, + "gen_feat_3": 489.55 + } + }, + { + "id": "t_payment2_gen_1", + "task_id": "t_payment2", + "provider_id": "p_gen_shared", + "name": "payment2 (Gen Shared)", + "features": { + "latency_ms": 92.24, + "cost_usd": 0.03, + "availability": 0.973888, + "gen_feat_1": 499.15, + "gen_feat_2": 0.505463, + "gen_feat_3": 506.65 + } + }, + { + "id": "t_authorize_gen_2", + "task_id": "t_authorize", + "provider_id": "p_wh1", + "name": "authorize (Gen p_wh1)", + "features": { + "latency_ms": 55.42, + "cost_usd": 0.01, + "availability": 0.991822, + "gen_feat_1": 506.11, + "gen_feat_2": 0.506997, + "gen_feat_3": 513.39 + } + }, + { + "id": "t_authorize_gen_3", + "task_id": "t_authorize", + "provider_id": "p_wh2", + "name": "authorize (Gen p_wh2)", + "features": { + "latency_ms": 56.53, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.13, + "gen_feat_2": 0.51125, + "gen_feat_3": 514.21 + } + }, + { + "id": "t_ok_gen_2", + "task_id": "t_ok", + "provider_id": "p_gen_1", + "name": "ok (Gen p_gen_1)", + "features": { + "latency_ms": 46.32, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 489.76, + "gen_feat_2": 0.491295, + "gen_feat_3": 499.11 + } + }, + { + "id": "t_ok_gen_3", + "task_id": "t_ok", + "provider_id": "p_gen_2", + "name": "ok (Gen p_gen_2)", + "features": { + "latency_ms": 44.18, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.78, + "gen_feat_2": 0.505694, + "gen_feat_3": 512.51 + } + }, + { + "id": "t_order1_gen_2", + "task_id": "t_order1", + "provider_id": "p_gen_3", + "name": "order1 (Gen p_gen_3)", + "features": { + "latency_ms": 65.65, + "cost_usd": 0.02, + "availability": 0.97648, + "gen_feat_1": 487.32, + "gen_feat_2": 0.507472, + "gen_feat_3": 497.45 + } + }, + { + "id": "t_order1_gen_3", + "task_id": "t_order1", + "provider_id": "p_gen_4", + "name": "order1 (Gen p_gen_4)", + "features": { + "latency_ms": 64.28, + "cost_usd": 0.02, + "availability": 0.972736, + "gen_feat_1": 486.2, + "gen_feat_2": 0.503633, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_receipt1_gen_2", + "task_id": "t_receipt1", + "provider_id": "p_gen_5", + "name": "receipt1 (Gen p_gen_5)", + "features": { + "latency_ms": 77.78, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.08, + "gen_feat_2": 0.510897, + "gen_feat_3": 486.77 + } + }, + { + "id": "t_receipt1_gen_3", + "task_id": "t_receipt1", + "provider_id": "p_store", + "name": "receipt1 (Gen p_store)", + "features": { + "latency_ms": 80.11, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 508.14, + "gen_feat_2": 0.486315, + "gen_feat_3": 489.94 + } + }, + { + "id": "t_bill1_gen_2", + "task_id": "t_bill1", + "provider_id": "p_bank", + "name": "bill1 (Gen p_bank)", + "features": { + "latency_ms": 77.07, + "cost_usd": 0.02, + "availability": 0.989736, + "gen_feat_1": 511.49, + "gen_feat_2": 0.492918, + "gen_feat_3": 514.68 + } + }, + { + "id": "t_bill1_gen_3", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1 (Gen p_wh1)", + "features": { + "latency_ms": 75.44, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 510.22, + "gen_feat_2": 0.514368, + "gen_feat_3": 505.69 + } + }, + { + "id": "t_payment1_gen_2", + "task_id": "t_payment1", + "provider_id": "p_wh2", + "name": "payment1 (Gen p_wh2)", + "features": { + "latency_ms": 90.7, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 490.92, + "gen_feat_2": 0.486279, + "gen_feat_3": 503.21 + } + }, + { + "id": "t_payment1_gen_3", + "task_id": "t_payment1", + "provider_id": "p_gen_1", + "name": "payment1 (Gen p_gen_1)", + "features": { + "latency_ms": 89.57, + "cost_usd": 0.03, + "availability": 0.990323, + "gen_feat_1": 509.49, + "gen_feat_2": 0.510492, + "gen_feat_3": 494.55 + } + }, + { + "id": "t_order2_gen_2", + "task_id": "t_order2", + "provider_id": "p_gen_2", + "name": "order2 (Gen p_gen_2)", + "features": { + "latency_ms": 71.14, + "cost_usd": 0.02, + "availability": 0.997499, + "gen_feat_1": 498.73, + "gen_feat_2": 0.505964, + "gen_feat_3": 492.35 + } + }, + { + "id": "t_order2_gen_3", + "task_id": "t_order2", + "provider_id": "p_gen_3", + "name": "order2 (Gen p_gen_3)", + "features": { + "latency_ms": 71.51, + "cost_usd": 0.02, + "availability": 0.978474, + "gen_feat_1": 495.91, + "gen_feat_2": 0.487052, + "gen_feat_3": 495.32 + } + }, + { + "id": "t_receipt2_gen_2", + "task_id": "t_receipt2", + "provider_id": "p_gen_4", + "name": "receipt2 (Gen p_gen_4)", + "features": { + "latency_ms": 85.95, + "cost_usd": 0.02, + "availability": 0.996183, + "gen_feat_1": 507.05, + "gen_feat_2": 0.506274, + "gen_feat_3": 489.81 + } + }, + { + "id": "t_receipt2_gen_3", + "task_id": "t_receipt2", + "provider_id": "p_gen_5", + "name": "receipt2 (Gen p_gen_5)", + "features": { + "latency_ms": 83.66, + "cost_usd": 0.01, + "availability": 0.973035, + "gen_feat_1": 491.17, + "gen_feat_2": 0.494194, + "gen_feat_3": 512.8 + } + }, + { + "id": "t_bill2_gen_2", + "task_id": "t_bill2", + "provider_id": "p_store", + "name": "bill2 (Gen p_store)", + "features": { + "latency_ms": 78.39, + "cost_usd": 0.02, + "availability": 0.991877, + "gen_feat_1": 493.57, + "gen_feat_2": 0.506639, + "gen_feat_3": 505.09 + } + }, + { + "id": "t_bill2_gen_3", + "task_id": "t_bill2", + "provider_id": "p_bank", + "name": "bill2 (Gen p_bank)", + "features": { + "latency_ms": 79.37, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 513.41, + "gen_feat_2": 0.503681, + "gen_feat_3": 510.14 + } + }, + { + "id": "t_payment2_gen_2", + "task_id": "t_payment2", + "provider_id": "p_wh1", + "name": "payment2 (Gen p_wh1)", + "features": { + "latency_ms": 93.89, + "cost_usd": 0.03, + "availability": 0.984789, + "gen_feat_1": 505.36, + "gen_feat_2": 0.49305, + "gen_feat_3": 514.13 + } + }, + { + "id": "t_payment2_gen_3", + "task_id": "t_payment2", + "provider_id": "p_wh2", + "name": "payment2 (Gen p_wh2)", + "features": { + "latency_ms": 92.96, + "cost_usd": 0.03, + "availability": 0.981651, + "gen_feat_1": 491.52, + "gen_feat_2": 0.503183, + "gen_feat_3": 492.47 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_authorize", + "kind": "TASK", + "task_id": "t_authorize" + }, + { + "id": "n_ok", + "kind": "TASK", + "task_id": "t_ok" + }, + { + "id": "n_parallel_orders", + "kind": "AND", + "children": [ + { + "id": "n_loop_wh1", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh1_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order1", + "kind": "TASK", + "task_id": "t_order1" + }, + { + "id": "n_wh1_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt1", + "kind": "TASK", + "task_id": "t_receipt1" + }, + { + "id": "n_wh1_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill1", + "kind": "TASK", + "task_id": "t_bill1" + }, + { + "id": "n_payment1", + "kind": "TASK", + "task_id": "t_payment1" + } + ] + } + ] + } + ] + } + }, + { + "id": "n_loop_wh2", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh2_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order2", + "kind": "TASK", + "task_id": "t_order2" + }, + { + "id": "n_wh2_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt2", + "kind": "TASK", + "task_id": "t_receipt2" + }, + { + "id": "n_wh2_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill2", + "kind": "TASK", + "task_id": "t_bill2" + }, + { + "id": "n_payment2", + "kind": "TASK", + "task_id": "t_payment2" + } + ] + } + ] + } + ] + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MULTI", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1" + ], + "weights": { + "availability": 0.34, + "cost_usd": 0.33, + "gen_feat_1": 0.33 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1318.72, + "hard": true + }, + { + "id": "gen_c_local_t_authorize_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_authorize" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.01, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_authorize", + "t_bill1" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_authorize", + "t_payment2" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/bultan2003-warehouse-example_multi_soft.json b/experimentation/instances/bultan2003-warehouse-example_multi_soft.json new file mode 100644 index 0000000..057d45f --- /dev/null +++ b/experimentation/instances/bultan2003-warehouse-example_multi_soft.json @@ -0,0 +1,989 @@ +{ + "metadata": { + "id": "bultan2003-warehouse-example_multi_soft", + "name": "Warehouse Composition example (Bultan et al. 2003) [multi, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Problem instance derived from Example 2.1 and Example 3.1 (store-bank-warehouse) in Bultan et al., WWW'03.", + "paper": { + "title": "Conversation Specification: A New Approach to Design and Analysis of E-Service Composition", + "authors": "T. Bultan et al.", + "year": 2003, + "doi": "10.1145/775152.775210" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "Latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_store", + "name": "Store" + }, + { + "id": "p_bank", + "name": "Bank" + }, + { + "id": "p_wh1", + "name": "Warehouse1" + }, + { + "id": "p_wh2", + "name": "Warehouse2" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_authorize", + "name": "Send authorize (store→bank)" + }, + { + "id": "t_ok", + "name": "Send ok (bank→store)" + }, + { + "id": "t_order1", + "name": "Send order1 (store→warehouse1)" + }, + { + "id": "t_receipt1", + "name": "Send receipt1 (warehouse1→store)" + }, + { + "id": "t_bill1", + "name": "Send bill1 (warehouse1→bank)" + }, + { + "id": "t_payment1", + "name": "Send payment1 (bank→warehouse1)" + }, + { + "id": "t_order2", + "name": "Send order2 (store→warehouse2)" + }, + { + "id": "t_receipt2", + "name": "Send receipt2 (warehouse2→store)" + }, + { + "id": "t_bill2", + "name": "Send bill2 (warehouse2→bank)" + }, + { + "id": "t_payment2", + "name": "Send payment2 (bank→warehouse2)" + } + ], + "candidates": [ + { + "id": "c_authorize_store_v1", + "task_id": "t_authorize", + "provider_id": "p_store", + "name": "authorize", + "features": { + "latency_ms": 55, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_ok_bank_v1", + "task_id": "t_ok", + "provider_id": "p_bank", + "name": "ok", + "features": { + "latency_ms": 45, + "cost_usd": 0.01, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order1_store_v1", + "task_id": "t_order1", + "provider_id": "p_store", + "name": "order1", + "features": { + "latency_ms": 65, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt1_wh1_v1", + "task_id": "t_receipt1", + "provider_id": "p_wh1", + "name": "receipt1", + "features": { + "latency_ms": 80, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill1_wh1_v1", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1", + "features": { + "latency_ms": 75, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment1_bank_v1", + "task_id": "t_payment1", + "provider_id": "p_bank", + "name": "payment1", + "features": { + "latency_ms": 90, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_order2_store_v1", + "task_id": "t_order2", + "provider_id": "p_store", + "name": "order2", + "features": { + "latency_ms": 70, + "cost_usd": 0.02, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_receipt2_wh2_v1", + "task_id": "t_receipt2", + "provider_id": "p_wh2", + "name": "receipt2", + "features": { + "latency_ms": 85, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_bill2_wh2_v1", + "task_id": "t_bill2", + "provider_id": "p_wh2", + "name": "bill2", + "features": { + "latency_ms": 78, + "cost_usd": 0.015, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_payment2_bank_v1", + "task_id": "t_payment2", + "provider_id": "p_bank", + "name": "payment2", + "features": { + "latency_ms": 95, + "cost_usd": 0.03, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_authorize_gen_1", + "task_id": "t_authorize", + "provider_id": "p_gen_shared", + "name": "authorize (Gen Shared)", + "features": { + "latency_ms": 56.03, + "cost_usd": 0.01, + "availability": 0.9942, + "gen_feat_1": 506.18, + "gen_feat_2": 0.499392, + "gen_feat_3": 514.16 + } + }, + { + "id": "t_ok_gen_1", + "task_id": "t_ok", + "provider_id": "p_gen_shared", + "name": "ok (Gen Shared)", + "features": { + "latency_ms": 45.04, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 498.62, + "gen_feat_2": 0.512982, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_order1_gen_1", + "task_id": "t_order1", + "provider_id": "p_gen_shared", + "name": "order1 (Gen Shared)", + "features": { + "latency_ms": 65.77, + "cost_usd": 0.02, + "availability": 0.969077, + "gen_feat_1": 495.0, + "gen_feat_2": 0.514614, + "gen_feat_3": 491.26 + } + }, + { + "id": "t_receipt1_gen_1", + "task_id": "t_receipt1", + "provider_id": "p_gen_shared", + "name": "receipt1 (Gen Shared)", + "features": { + "latency_ms": 78.06, + "cost_usd": 0.02, + "availability": 0.967727, + "gen_feat_1": 500.39, + "gen_feat_2": 0.485136, + "gen_feat_3": 489.78 + } + }, + { + "id": "t_bill1_gen_1", + "task_id": "t_bill1", + "provider_id": "p_gen_shared", + "name": "bill1 (Gen Shared)", + "features": { + "latency_ms": 74.23, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 499.46, + "gen_feat_2": 0.510726, + "gen_feat_3": 507.43 + } + }, + { + "id": "t_payment1_gen_1", + "task_id": "t_payment1", + "provider_id": "p_gen_shared", + "name": "payment1 (Gen Shared)", + "features": { + "latency_ms": 92.58, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 485.22, + "gen_feat_2": 0.502923, + "gen_feat_3": 500.11 + } + }, + { + "id": "t_order2_gen_1", + "task_id": "t_order2", + "provider_id": "p_gen_shared", + "name": "order2 (Gen Shared)", + "features": { + "latency_ms": 69.52, + "cost_usd": 0.02, + "availability": 0.98773, + "gen_feat_1": 498.95, + "gen_feat_2": 0.488362, + "gen_feat_3": 485.48 + } + }, + { + "id": "t_receipt2_gen_1", + "task_id": "t_receipt2", + "provider_id": "p_gen_shared", + "name": "receipt2 (Gen Shared)", + "features": { + "latency_ms": 82.92, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 494.35, + "gen_feat_2": 0.50285, + "gen_feat_3": 507.12 + } + }, + { + "id": "t_bill2_gen_1", + "task_id": "t_bill2", + "provider_id": "p_gen_shared", + "name": "bill2 (Gen Shared)", + "features": { + "latency_ms": 79.01, + "cost_usd": 0.01, + "availability": 0.984644, + "gen_feat_1": 488.32, + "gen_feat_2": 0.499763, + "gen_feat_3": 489.55 + } + }, + { + "id": "t_payment2_gen_1", + "task_id": "t_payment2", + "provider_id": "p_gen_shared", + "name": "payment2 (Gen Shared)", + "features": { + "latency_ms": 92.24, + "cost_usd": 0.03, + "availability": 0.973888, + "gen_feat_1": 499.15, + "gen_feat_2": 0.505463, + "gen_feat_3": 506.65 + } + }, + { + "id": "t_authorize_gen_2", + "task_id": "t_authorize", + "provider_id": "p_wh1", + "name": "authorize (Gen p_wh1)", + "features": { + "latency_ms": 55.42, + "cost_usd": 0.01, + "availability": 0.991822, + "gen_feat_1": 506.11, + "gen_feat_2": 0.506997, + "gen_feat_3": 513.39 + } + }, + { + "id": "t_authorize_gen_3", + "task_id": "t_authorize", + "provider_id": "p_wh2", + "name": "authorize (Gen p_wh2)", + "features": { + "latency_ms": 56.53, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.13, + "gen_feat_2": 0.51125, + "gen_feat_3": 514.21 + } + }, + { + "id": "t_ok_gen_2", + "task_id": "t_ok", + "provider_id": "p_gen_1", + "name": "ok (Gen p_gen_1)", + "features": { + "latency_ms": 46.32, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 489.76, + "gen_feat_2": 0.491295, + "gen_feat_3": 499.11 + } + }, + { + "id": "t_ok_gen_3", + "task_id": "t_ok", + "provider_id": "p_gen_2", + "name": "ok (Gen p_gen_2)", + "features": { + "latency_ms": 44.18, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.78, + "gen_feat_2": 0.505694, + "gen_feat_3": 512.51 + } + }, + { + "id": "t_order1_gen_2", + "task_id": "t_order1", + "provider_id": "p_gen_3", + "name": "order1 (Gen p_gen_3)", + "features": { + "latency_ms": 65.65, + "cost_usd": 0.02, + "availability": 0.97648, + "gen_feat_1": 487.32, + "gen_feat_2": 0.507472, + "gen_feat_3": 497.45 + } + }, + { + "id": "t_order1_gen_3", + "task_id": "t_order1", + "provider_id": "p_gen_4", + "name": "order1 (Gen p_gen_4)", + "features": { + "latency_ms": 64.28, + "cost_usd": 0.02, + "availability": 0.972736, + "gen_feat_1": 486.2, + "gen_feat_2": 0.503633, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_receipt1_gen_2", + "task_id": "t_receipt1", + "provider_id": "p_gen_5", + "name": "receipt1 (Gen p_gen_5)", + "features": { + "latency_ms": 77.78, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 512.08, + "gen_feat_2": 0.510897, + "gen_feat_3": 486.77 + } + }, + { + "id": "t_receipt1_gen_3", + "task_id": "t_receipt1", + "provider_id": "p_store", + "name": "receipt1 (Gen p_store)", + "features": { + "latency_ms": 80.11, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 508.14, + "gen_feat_2": 0.486315, + "gen_feat_3": 489.94 + } + }, + { + "id": "t_bill1_gen_2", + "task_id": "t_bill1", + "provider_id": "p_bank", + "name": "bill1 (Gen p_bank)", + "features": { + "latency_ms": 77.07, + "cost_usd": 0.02, + "availability": 0.989736, + "gen_feat_1": 511.49, + "gen_feat_2": 0.492918, + "gen_feat_3": 514.68 + } + }, + { + "id": "t_bill1_gen_3", + "task_id": "t_bill1", + "provider_id": "p_wh1", + "name": "bill1 (Gen p_wh1)", + "features": { + "latency_ms": 75.44, + "cost_usd": 0.01, + "availability": 1.0, + "gen_feat_1": 510.22, + "gen_feat_2": 0.514368, + "gen_feat_3": 505.69 + } + }, + { + "id": "t_payment1_gen_2", + "task_id": "t_payment1", + "provider_id": "p_wh2", + "name": "payment1 (Gen p_wh2)", + "features": { + "latency_ms": 90.7, + "cost_usd": 0.03, + "availability": 1.0, + "gen_feat_1": 490.92, + "gen_feat_2": 0.486279, + "gen_feat_3": 503.21 + } + }, + { + "id": "t_payment1_gen_3", + "task_id": "t_payment1", + "provider_id": "p_gen_1", + "name": "payment1 (Gen p_gen_1)", + "features": { + "latency_ms": 89.57, + "cost_usd": 0.03, + "availability": 0.990323, + "gen_feat_1": 509.49, + "gen_feat_2": 0.510492, + "gen_feat_3": 494.55 + } + }, + { + "id": "t_order2_gen_2", + "task_id": "t_order2", + "provider_id": "p_gen_2", + "name": "order2 (Gen p_gen_2)", + "features": { + "latency_ms": 71.14, + "cost_usd": 0.02, + "availability": 0.997499, + "gen_feat_1": 498.73, + "gen_feat_2": 0.505964, + "gen_feat_3": 492.35 + } + }, + { + "id": "t_order2_gen_3", + "task_id": "t_order2", + "provider_id": "p_gen_3", + "name": "order2 (Gen p_gen_3)", + "features": { + "latency_ms": 71.51, + "cost_usd": 0.02, + "availability": 0.978474, + "gen_feat_1": 495.91, + "gen_feat_2": 0.487052, + "gen_feat_3": 495.32 + } + }, + { + "id": "t_receipt2_gen_2", + "task_id": "t_receipt2", + "provider_id": "p_gen_4", + "name": "receipt2 (Gen p_gen_4)", + "features": { + "latency_ms": 85.95, + "cost_usd": 0.02, + "availability": 0.996183, + "gen_feat_1": 507.05, + "gen_feat_2": 0.506274, + "gen_feat_3": 489.81 + } + }, + { + "id": "t_receipt2_gen_3", + "task_id": "t_receipt2", + "provider_id": "p_gen_5", + "name": "receipt2 (Gen p_gen_5)", + "features": { + "latency_ms": 83.66, + "cost_usd": 0.01, + "availability": 0.973035, + "gen_feat_1": 491.17, + "gen_feat_2": 0.494194, + "gen_feat_3": 512.8 + } + }, + { + "id": "t_bill2_gen_2", + "task_id": "t_bill2", + "provider_id": "p_store", + "name": "bill2 (Gen p_store)", + "features": { + "latency_ms": 78.39, + "cost_usd": 0.02, + "availability": 0.991877, + "gen_feat_1": 493.57, + "gen_feat_2": 0.506639, + "gen_feat_3": 505.09 + } + }, + { + "id": "t_bill2_gen_3", + "task_id": "t_bill2", + "provider_id": "p_bank", + "name": "bill2 (Gen p_bank)", + "features": { + "latency_ms": 79.37, + "cost_usd": 0.02, + "availability": 1.0, + "gen_feat_1": 513.41, + "gen_feat_2": 0.503681, + "gen_feat_3": 510.14 + } + }, + { + "id": "t_payment2_gen_2", + "task_id": "t_payment2", + "provider_id": "p_wh1", + "name": "payment2 (Gen p_wh1)", + "features": { + "latency_ms": 93.89, + "cost_usd": 0.03, + "availability": 0.984789, + "gen_feat_1": 505.36, + "gen_feat_2": 0.49305, + "gen_feat_3": 514.13 + } + }, + { + "id": "t_payment2_gen_3", + "task_id": "t_payment2", + "provider_id": "p_wh2", + "name": "payment2 (Gen p_wh2)", + "features": { + "latency_ms": 92.96, + "cost_usd": 0.03, + "availability": 0.981651, + "gen_feat_1": 491.52, + "gen_feat_2": 0.503183, + "gen_feat_3": 492.47 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_authorize", + "kind": "TASK", + "task_id": "t_authorize" + }, + { + "id": "n_ok", + "kind": "TASK", + "task_id": "t_ok" + }, + { + "id": "n_parallel_orders", + "kind": "AND", + "children": [ + { + "id": "n_loop_wh1", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh1_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order1", + "kind": "TASK", + "task_id": "t_order1" + }, + { + "id": "n_wh1_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt1", + "kind": "TASK", + "task_id": "t_receipt1" + }, + { + "id": "n_wh1_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill1", + "kind": "TASK", + "task_id": "t_bill1" + }, + { + "id": "n_payment1", + "kind": "TASK", + "task_id": "t_payment1" + } + ] + } + ] + } + ] + } + }, + { + "id": "n_loop_wh2", + "kind": "LOOP", + "bounds": { + "min": 0, + "max": 5 + }, + "body": { + "id": "n_wh2_iter_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_order2", + "kind": "TASK", + "task_id": "t_order2" + }, + { + "id": "n_wh2_after_order", + "kind": "AND", + "children": [ + { + "id": "n_receipt2", + "kind": "TASK", + "task_id": "t_receipt2" + }, + { + "id": "n_wh2_billpay", + "kind": "SEQ", + "children": [ + { + "id": "n_bill2", + "kind": "TASK", + "task_id": "t_bill2" + }, + { + "id": "n_payment2", + "kind": "TASK", + "task_id": "t_payment2" + } + ] + } + ] + } + ] + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MULTI", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1" + ], + "weights": { + "availability": 0.34, + "cost_usd": 0.33, + "gen_feat_1": 0.33 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1318.72, + "hard": false + }, + { + "id": "gen_c_local_t_authorize_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_authorize" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.01, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_authorize", + "t_bill1" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_authorize", + "t_payment2" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/cremaschi2018-textbook-access_many_hard.json b/experimentation/instances/cremaschi2018-textbook-access_many_hard.json new file mode 100644 index 0000000..ea39891 --- /dev/null +++ b/experimentation/instances/cremaschi2018-textbook-access_many_hard.json @@ -0,0 +1,1202 @@ +{ + "metadata": { + "id": "cremaschi2018-textbook-access_many_hard", + "name": "Book info retrieval (Cremaschi et al. 2018) [many, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "QoS-aware instance derived from the running example in 'A Practical Approach to Services Composition Through Light Semantic Descriptions' (ESOCC 2018). QoS values are illustrative placeholders.", + "paper": { + "title": "A Practical Approach to Services Composition Through Light Semantic Descriptions", + "authors": "M. Cremaschi et al.", + "year": 2018, + "doi": "10.1007/978-3-319-99819-0_10" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Monetary cost per execution", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10 + } + }, + { + "id": "availability", + "name": "Service availability", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_google", + "name": "Google" + }, + { + "id": "p_amazon", + "name": "Amazon" + }, + { + "id": "p_unimib", + "name": "University of Milan - Bicocca (OPAC library)" + }, + { + "id": "p_archive", + "name": "Archive.org" + }, + { + "id": "p_local", + "name": "Local Application" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_books", + "name": "Retrieve book metadata from title (ISBN/author/title)" + }, + { + "id": "t_market", + "name": "Check e-commerce availability/price by ISBN" + }, + { + "id": "t_library", + "name": "Check library availability and retrieve library address" + }, + { + "id": "t_geocoding", + "name": "Geocode library address into coordinates" + }, + { + "id": "t_transit", + "name": "Retrieve public transport options to the library" + }, + { + "id": "t_archive", + "name": "Check free eBook availability (Archive.org)" + } + ], + "candidates": [ + { + "id": "c_google_books_api", + "task_id": "t_books", + "provider_id": "p_google", + "name": "Google Books API", + "features": { + "latency_ms": 250, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_amazon_market_api", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API", + "features": { + "latency_ms": 400, + "cost_usd": 0.001, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_opac_library_api", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API", + "features": { + "latency_ms": 350, + "cost_usd": 0.0001, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_geocoding_api", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API", + "features": { + "latency_ms": 300, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_transit_api", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API", + "features": { + "latency_ms": 450, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_archive_api", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API", + "features": { + "latency_ms": 500, + "cost_usd": 0.0001, + "availability": 0.97, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_books_gen_1", + "task_id": "t_books", + "provider_id": "p_gen_shared", + "name": "Google Books API (Gen Shared)", + "features": { + "latency_ms": 250.27, + "cost_usd": 0.0, + "availability": 0.970656, + "gen_feat_1": 507.35, + "gen_feat_2": 0.498346, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_market_gen_1", + "task_id": "t_market", + "provider_id": "p_gen_shared", + "name": "Amazon Market API (Gen Shared)", + "features": { + "latency_ms": 410.3, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.37, + "gen_feat_2": 0.4873, + "gen_feat_3": 499.78 + } + }, + { + "id": "t_library_gen_1", + "task_id": "t_library", + "provider_id": "p_gen_shared", + "name": "OPAC Library API (Gen Shared)", + "features": { + "latency_ms": 350.22, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 503.36, + "gen_feat_2": 0.490142, + "gen_feat_3": 513.01 + } + }, + { + "id": "t_geocoding_gen_1", + "task_id": "t_geocoding", + "provider_id": "p_gen_shared", + "name": "Google Maps Geocoding API (Gen Shared)", + "features": { + "latency_ms": 299.52, + "cost_usd": 0.0, + "availability": 0.970921, + "gen_feat_1": 509.42, + "gen_feat_2": 0.491433, + "gen_feat_3": 503.84 + } + }, + { + "id": "t_transit_gen_1", + "task_id": "t_transit", + "provider_id": "p_gen_shared", + "name": "Google Transit API (Gen Shared)", + "features": { + "latency_ms": 457.93, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.8, + "gen_feat_2": 0.5146, + "gen_feat_3": 509.74 + } + }, + { + "id": "t_archive_gen_1", + "task_id": "t_archive", + "provider_id": "p_gen_shared", + "name": "Archive.org API (Gen Shared)", + "features": { + "latency_ms": 494.4, + "cost_usd": 0.0, + "availability": 0.973217, + "gen_feat_1": 486.21, + "gen_feat_2": 0.487758, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_books_gen_2", + "task_id": "t_books", + "provider_id": "p_unimib", + "name": "Google Books API (Gen p_unimib)", + "features": { + "latency_ms": 251.51, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.43, + "gen_feat_2": 0.49659, + "gen_feat_3": 492.56 + } + }, + { + "id": "t_books_gen_3", + "task_id": "t_books", + "provider_id": "p_archive", + "name": "Google Books API (Gen p_archive)", + "features": { + "latency_ms": 253.59, + "cost_usd": 0.0, + "availability": 0.976832, + "gen_feat_1": 498.31, + "gen_feat_2": 0.504989, + "gen_feat_3": 485.73 + } + }, + { + "id": "t_books_gen_4", + "task_id": "t_books", + "provider_id": "p_local", + "name": "Google Books API (Gen p_local)", + "features": { + "latency_ms": 253.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 496.81, + "gen_feat_2": 0.509742, + "gen_feat_3": 503.82 + } + }, + { + "id": "t_books_gen_5", + "task_id": "t_books", + "provider_id": "p_gen_1", + "name": "Google Books API (Gen p_gen_1)", + "features": { + "latency_ms": 243.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.29, + "gen_feat_2": 0.497801, + "gen_feat_3": 491.8 + } + }, + { + "id": "t_books_gen_6", + "task_id": "t_books", + "provider_id": "p_gen_2", + "name": "Google Books API (Gen p_gen_2)", + "features": { + "latency_ms": 249.33, + "cost_usd": 0.0, + "availability": 0.968324, + "gen_feat_1": 500.1, + "gen_feat_2": 0.489322, + "gen_feat_3": 486.96 + } + }, + { + "id": "t_books_gen_7", + "task_id": "t_books", + "provider_id": "p_gen_3", + "name": "Google Books API (Gen p_gen_3)", + "features": { + "latency_ms": 244.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.49, + "gen_feat_2": 0.509901, + "gen_feat_3": 510.32 + } + }, + { + "id": "t_books_gen_8", + "task_id": "t_books", + "provider_id": "p_gen_4", + "name": "Google Books API (Gen p_gen_4)", + "features": { + "latency_ms": 249.93, + "cost_usd": 0.0, + "availability": 0.984683, + "gen_feat_1": 503.61, + "gen_feat_2": 0.501017, + "gen_feat_3": 501.49 + } + }, + { + "id": "t_books_gen_9", + "task_id": "t_books", + "provider_id": "p_gen_5", + "name": "Google Books API (Gen p_gen_5)", + "features": { + "latency_ms": 252.75, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 505.53, + "gen_feat_2": 0.491572, + "gen_feat_3": 506.63 + } + }, + { + "id": "t_market_gen_2", + "task_id": "t_market", + "provider_id": "p_google", + "name": "Amazon Market API (Gen p_google)", + "features": { + "latency_ms": 390.51, + "cost_usd": 0.0, + "availability": 0.974193, + "gen_feat_1": 514.03, + "gen_feat_2": 0.504606, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_market_gen_3", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API (Gen p_amazon)", + "features": { + "latency_ms": 390.29, + "cost_usd": 0.0, + "availability": 0.964065, + "gen_feat_1": 490.39, + "gen_feat_2": 0.510618, + "gen_feat_3": 500.06 + } + }, + { + "id": "t_market_gen_4", + "task_id": "t_market", + "provider_id": "p_unimib", + "name": "Amazon Market API (Gen p_unimib)", + "features": { + "latency_ms": 403.22, + "cost_usd": 0.0, + "availability": 0.98629, + "gen_feat_1": 506.11, + "gen_feat_2": 0.504836, + "gen_feat_3": 513.95 + } + }, + { + "id": "t_market_gen_5", + "task_id": "t_market", + "provider_id": "p_archive", + "name": "Amazon Market API (Gen p_archive)", + "features": { + "latency_ms": 392.94, + "cost_usd": 0.0, + "availability": 0.963527, + "gen_feat_1": 512.48, + "gen_feat_2": 0.514296, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_market_gen_6", + "task_id": "t_market", + "provider_id": "p_local", + "name": "Amazon Market API (Gen p_local)", + "features": { + "latency_ms": 393.03, + "cost_usd": 0.0, + "availability": 0.981369, + "gen_feat_1": 488.34, + "gen_feat_2": 0.514668, + "gen_feat_3": 505.0 + } + }, + { + "id": "t_market_gen_7", + "task_id": "t_market", + "provider_id": "p_gen_1", + "name": "Amazon Market API (Gen p_gen_1)", + "features": { + "latency_ms": 411.7, + "cost_usd": 0.0, + "availability": 0.985823, + "gen_feat_1": 500.86, + "gen_feat_2": 0.497755, + "gen_feat_3": 497.03 + } + }, + { + "id": "t_market_gen_8", + "task_id": "t_market", + "provider_id": "p_gen_2", + "name": "Amazon Market API (Gen p_gen_2)", + "features": { + "latency_ms": 402.71, + "cost_usd": 0.0, + "availability": 0.991509, + "gen_feat_1": 505.13, + "gen_feat_2": 0.49775, + "gen_feat_3": 491.63 + } + }, + { + "id": "t_market_gen_9", + "task_id": "t_market", + "provider_id": "p_gen_3", + "name": "Amazon Market API (Gen p_gen_3)", + "features": { + "latency_ms": 402.55, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 510.3, + "gen_feat_2": 0.501032, + "gen_feat_3": 505.68 + } + }, + { + "id": "t_library_gen_2", + "task_id": "t_library", + "provider_id": "p_gen_4", + "name": "OPAC Library API (Gen p_gen_4)", + "features": { + "latency_ms": 345.85, + "cost_usd": 0.0, + "availability": 0.97661, + "gen_feat_1": 508.48, + "gen_feat_2": 0.509068, + "gen_feat_3": 505.91 + } + }, + { + "id": "t_library_gen_3", + "task_id": "t_library", + "provider_id": "p_gen_5", + "name": "OPAC Library API (Gen p_gen_5)", + "features": { + "latency_ms": 357.65, + "cost_usd": 0.0, + "availability": 0.995668, + "gen_feat_1": 511.52, + "gen_feat_2": 0.489245, + "gen_feat_3": 489.95 + } + }, + { + "id": "t_library_gen_4", + "task_id": "t_library", + "provider_id": "p_google", + "name": "OPAC Library API (Gen p_google)", + "features": { + "latency_ms": 347.46, + "cost_usd": 0.0, + "availability": 0.961356, + "gen_feat_1": 510.48, + "gen_feat_2": 0.509522, + "gen_feat_3": 510.51 + } + }, + { + "id": "t_library_gen_5", + "task_id": "t_library", + "provider_id": "p_amazon", + "name": "OPAC Library API (Gen p_amazon)", + "features": { + "latency_ms": 346.07, + "cost_usd": 0.0, + "availability": 0.99049, + "gen_feat_1": 510.53, + "gen_feat_2": 0.488512, + "gen_feat_3": 513.85 + } + }, + { + "id": "t_library_gen_6", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API (Gen p_unimib)", + "features": { + "latency_ms": 353.12, + "cost_usd": 0.0, + "availability": 0.966548, + "gen_feat_1": 500.27, + "gen_feat_2": 0.497436, + "gen_feat_3": 511.73 + } + }, + { + "id": "t_library_gen_7", + "task_id": "t_library", + "provider_id": "p_archive", + "name": "OPAC Library API (Gen p_archive)", + "features": { + "latency_ms": 356.85, + "cost_usd": 0.0, + "availability": 0.993546, + "gen_feat_1": 510.3, + "gen_feat_2": 0.513619, + "gen_feat_3": 511.4 + } + }, + { + "id": "t_library_gen_8", + "task_id": "t_library", + "provider_id": "p_local", + "name": "OPAC Library API (Gen p_local)", + "features": { + "latency_ms": 357.15, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.06, + "gen_feat_2": 0.487388, + "gen_feat_3": 498.18 + } + }, + { + "id": "t_library_gen_9", + "task_id": "t_library", + "provider_id": "p_gen_1", + "name": "OPAC Library API (Gen p_gen_1)", + "features": { + "latency_ms": 355.46, + "cost_usd": 0.0, + "availability": 0.970169, + "gen_feat_1": 490.3, + "gen_feat_2": 0.497807, + "gen_feat_3": 495.16 + } + }, + { + "id": "t_geocoding_gen_2", + "task_id": "t_geocoding", + "provider_id": "p_gen_2", + "name": "Google Maps Geocoding API (Gen p_gen_2)", + "features": { + "latency_ms": 293.3, + "cost_usd": 0.0, + "availability": 0.974652, + "gen_feat_1": 508.37, + "gen_feat_2": 0.500348, + "gen_feat_3": 495.48 + } + }, + { + "id": "t_geocoding_gen_3", + "task_id": "t_geocoding", + "provider_id": "p_gen_3", + "name": "Google Maps Geocoding API (Gen p_gen_3)", + "features": { + "latency_ms": 298.14, + "cost_usd": 0.0, + "availability": 0.985441, + "gen_feat_1": 501.06, + "gen_feat_2": 0.508714, + "gen_feat_3": 511.67 + } + }, + { + "id": "t_geocoding_gen_4", + "task_id": "t_geocoding", + "provider_id": "p_gen_4", + "name": "Google Maps Geocoding API (Gen p_gen_4)", + "features": { + "latency_ms": 296.31, + "cost_usd": 0.0, + "availability": 0.970937, + "gen_feat_1": 504.66, + "gen_feat_2": 0.485959, + "gen_feat_3": 506.47 + } + }, + { + "id": "t_geocoding_gen_5", + "task_id": "t_geocoding", + "provider_id": "p_gen_5", + "name": "Google Maps Geocoding API (Gen p_gen_5)", + "features": { + "latency_ms": 292.44, + "cost_usd": 0.0, + "availability": 0.970116, + "gen_feat_1": 506.54, + "gen_feat_2": 0.485388, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_geocoding_gen_6", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API (Gen p_google)", + "features": { + "latency_ms": 296.68, + "cost_usd": 0.0, + "availability": 0.979126, + "gen_feat_1": 503.49, + "gen_feat_2": 0.509299, + "gen_feat_3": 501.7 + } + }, + { + "id": "t_geocoding_gen_7", + "task_id": "t_geocoding", + "provider_id": "p_amazon", + "name": "Google Maps Geocoding API (Gen p_amazon)", + "features": { + "latency_ms": 299.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.43, + "gen_feat_2": 0.485447, + "gen_feat_3": 504.86 + } + }, + { + "id": "t_geocoding_gen_8", + "task_id": "t_geocoding", + "provider_id": "p_unimib", + "name": "Google Maps Geocoding API (Gen p_unimib)", + "features": { + "latency_ms": 291.86, + "cost_usd": 0.0, + "availability": 0.967929, + "gen_feat_1": 500.94, + "gen_feat_2": 0.487602, + "gen_feat_3": 501.12 + } + }, + { + "id": "t_geocoding_gen_9", + "task_id": "t_geocoding", + "provider_id": "p_archive", + "name": "Google Maps Geocoding API (Gen p_archive)", + "features": { + "latency_ms": 303.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.48, + "gen_feat_2": 0.494252, + "gen_feat_3": 501.53 + } + }, + { + "id": "t_transit_gen_2", + "task_id": "t_transit", + "provider_id": "p_local", + "name": "Google Transit API (Gen p_local)", + "features": { + "latency_ms": 447.81, + "cost_usd": 0.0, + "availability": 0.97876, + "gen_feat_1": 487.34, + "gen_feat_2": 0.494893, + "gen_feat_3": 492.66 + } + }, + { + "id": "t_transit_gen_3", + "task_id": "t_transit", + "provider_id": "p_gen_1", + "name": "Google Transit API (Gen p_gen_1)", + "features": { + "latency_ms": 454.73, + "cost_usd": 0.0, + "availability": 0.982378, + "gen_feat_1": 508.31, + "gen_feat_2": 0.486183, + "gen_feat_3": 501.39 + } + }, + { + "id": "t_transit_gen_4", + "task_id": "t_transit", + "provider_id": "p_gen_2", + "name": "Google Transit API (Gen p_gen_2)", + "features": { + "latency_ms": 463.1, + "cost_usd": 0.0, + "availability": 0.967212, + "gen_feat_1": 512.89, + "gen_feat_2": 0.512956, + "gen_feat_3": 495.23 + } + }, + { + "id": "t_transit_gen_5", + "task_id": "t_transit", + "provider_id": "p_gen_3", + "name": "Google Transit API (Gen p_gen_3)", + "features": { + "latency_ms": 456.23, + "cost_usd": 0.0, + "availability": 0.965992, + "gen_feat_1": 490.49, + "gen_feat_2": 0.508133, + "gen_feat_3": 504.92 + } + }, + { + "id": "t_transit_gen_6", + "task_id": "t_transit", + "provider_id": "p_gen_4", + "name": "Google Transit API (Gen p_gen_4)", + "features": { + "latency_ms": 440.18, + "cost_usd": 0.0, + "availability": 0.991733, + "gen_feat_1": 490.83, + "gen_feat_2": 0.504993, + "gen_feat_3": 492.89 + } + }, + { + "id": "t_transit_gen_7", + "task_id": "t_transit", + "provider_id": "p_gen_5", + "name": "Google Transit API (Gen p_gen_5)", + "features": { + "latency_ms": 462.92, + "cost_usd": 0.0, + "availability": 0.996902, + "gen_feat_1": 511.69, + "gen_feat_2": 0.506072, + "gen_feat_3": 487.84 + } + }, + { + "id": "t_transit_gen_8", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API (Gen p_google)", + "features": { + "latency_ms": 437.2, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 486.88, + "gen_feat_2": 0.486007, + "gen_feat_3": 512.05 + } + }, + { + "id": "t_transit_gen_9", + "task_id": "t_transit", + "provider_id": "p_amazon", + "name": "Google Transit API (Gen p_amazon)", + "features": { + "latency_ms": 454.11, + "cost_usd": 0.0, + "availability": 0.993251, + "gen_feat_1": 496.88, + "gen_feat_2": 0.494363, + "gen_feat_3": 508.7 + } + }, + { + "id": "t_archive_gen_2", + "task_id": "t_archive", + "provider_id": "p_unimib", + "name": "Archive.org API (Gen p_unimib)", + "features": { + "latency_ms": 491.38, + "cost_usd": 0.0, + "availability": 0.97419, + "gen_feat_1": 488.94, + "gen_feat_2": 0.490436, + "gen_feat_3": 502.27 + } + }, + { + "id": "t_archive_gen_3", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API (Gen p_archive)", + "features": { + "latency_ms": 493.0, + "cost_usd": 0.0, + "availability": 0.974135, + "gen_feat_1": 509.85, + "gen_feat_2": 0.501448, + "gen_feat_3": 508.14 + } + }, + { + "id": "t_archive_gen_4", + "task_id": "t_archive", + "provider_id": "p_local", + "name": "Archive.org API (Gen p_local)", + "features": { + "latency_ms": 506.7, + "cost_usd": 0.0, + "availability": 0.950007, + "gen_feat_1": 485.3, + "gen_feat_2": 0.506074, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_archive_gen_5", + "task_id": "t_archive", + "provider_id": "p_gen_1", + "name": "Archive.org API (Gen p_gen_1)", + "features": { + "latency_ms": 489.16, + "cost_usd": 0.0, + "availability": 0.997048, + "gen_feat_1": 498.8, + "gen_feat_2": 0.513697, + "gen_feat_3": 499.99 + } + }, + { + "id": "t_archive_gen_6", + "task_id": "t_archive", + "provider_id": "p_gen_2", + "name": "Archive.org API (Gen p_gen_2)", + "features": { + "latency_ms": 490.4, + "cost_usd": 0.0, + "availability": 0.989264, + "gen_feat_1": 499.32, + "gen_feat_2": 0.492021, + "gen_feat_3": 511.64 + } + }, + { + "id": "t_archive_gen_7", + "task_id": "t_archive", + "provider_id": "p_gen_3", + "name": "Archive.org API (Gen p_gen_3)", + "features": { + "latency_ms": 493.82, + "cost_usd": 0.0, + "availability": 0.963902, + "gen_feat_1": 513.54, + "gen_feat_2": 0.514704, + "gen_feat_3": 488.6 + } + }, + { + "id": "t_archive_gen_8", + "task_id": "t_archive", + "provider_id": "p_gen_4", + "name": "Archive.org API (Gen p_gen_4)", + "features": { + "latency_ms": 501.92, + "cost_usd": 0.0, + "availability": 0.987176, + "gen_feat_1": 487.31, + "gen_feat_2": 0.5052, + "gen_feat_3": 512.55 + } + }, + { + "id": "t_archive_gen_9", + "task_id": "t_archive", + "provider_id": "p_gen_5", + "name": "Archive.org API (Gen p_gen_5)", + "features": { + "latency_ms": 497.11, + "cost_usd": 0.0, + "availability": 0.959066, + "gen_feat_1": 489.18, + "gen_feat_2": 0.487091, + "gen_feat_3": 488.33 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_books", + "kind": "TASK", + "task_id": "t_books" + }, + { + "id": "n_parallel_options", + "kind": "AND", + "children": [ + { + "id": "n_amazon", + "kind": "TASK", + "task_id": "t_market" + }, + { + "id": "n_library_trip", + "kind": "SEQ", + "children": [ + { + "id": "n_opac", + "kind": "TASK", + "task_id": "t_library" + }, + { + "id": "n_geocode", + "kind": "TASK", + "task_id": "t_geocoding" + }, + { + "id": "n_transit", + "kind": "TASK", + "task_id": "t_transit" + } + ] + }, + { + "id": "n_archive", + "kind": "TASK", + "task_id": "t_archive" + } + ] + }, + { + "id": "n_report", + "kind": "ELEMENT", + "description": "Assemble final textbook access report" + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MANY", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1357.94, + "hard": true + }, + { + "id": "gen_c_local_t_archive_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_archive" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_books", + "t_geocoding" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_archive", + "t_books" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/cremaschi2018-textbook-access_many_soft.json b/experimentation/instances/cremaschi2018-textbook-access_many_soft.json new file mode 100644 index 0000000..cdf169d --- /dev/null +++ b/experimentation/instances/cremaschi2018-textbook-access_many_soft.json @@ -0,0 +1,1202 @@ +{ + "metadata": { + "id": "cremaschi2018-textbook-access_many_soft", + "name": "Book info retrieval (Cremaschi et al. 2018) [many, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "QoS-aware instance derived from the running example in 'A Practical Approach to Services Composition Through Light Semantic Descriptions' (ESOCC 2018). QoS values are illustrative placeholders.", + "paper": { + "title": "A Practical Approach to Services Composition Through Light Semantic Descriptions", + "authors": "M. Cremaschi et al.", + "year": 2018, + "doi": "10.1007/978-3-319-99819-0_10" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Monetary cost per execution", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10 + } + }, + { + "id": "availability", + "name": "Service availability", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_google", + "name": "Google" + }, + { + "id": "p_amazon", + "name": "Amazon" + }, + { + "id": "p_unimib", + "name": "University of Milan - Bicocca (OPAC library)" + }, + { + "id": "p_archive", + "name": "Archive.org" + }, + { + "id": "p_local", + "name": "Local Application" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_books", + "name": "Retrieve book metadata from title (ISBN/author/title)" + }, + { + "id": "t_market", + "name": "Check e-commerce availability/price by ISBN" + }, + { + "id": "t_library", + "name": "Check library availability and retrieve library address" + }, + { + "id": "t_geocoding", + "name": "Geocode library address into coordinates" + }, + { + "id": "t_transit", + "name": "Retrieve public transport options to the library" + }, + { + "id": "t_archive", + "name": "Check free eBook availability (Archive.org)" + } + ], + "candidates": [ + { + "id": "c_google_books_api", + "task_id": "t_books", + "provider_id": "p_google", + "name": "Google Books API", + "features": { + "latency_ms": 250, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_amazon_market_api", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API", + "features": { + "latency_ms": 400, + "cost_usd": 0.001, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_opac_library_api", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API", + "features": { + "latency_ms": 350, + "cost_usd": 0.0001, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_geocoding_api", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API", + "features": { + "latency_ms": 300, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_transit_api", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API", + "features": { + "latency_ms": 450, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_archive_api", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API", + "features": { + "latency_ms": 500, + "cost_usd": 0.0001, + "availability": 0.97, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_books_gen_1", + "task_id": "t_books", + "provider_id": "p_gen_shared", + "name": "Google Books API (Gen Shared)", + "features": { + "latency_ms": 250.27, + "cost_usd": 0.0, + "availability": 0.970656, + "gen_feat_1": 507.35, + "gen_feat_2": 0.498346, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_market_gen_1", + "task_id": "t_market", + "provider_id": "p_gen_shared", + "name": "Amazon Market API (Gen Shared)", + "features": { + "latency_ms": 410.3, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.37, + "gen_feat_2": 0.4873, + "gen_feat_3": 499.78 + } + }, + { + "id": "t_library_gen_1", + "task_id": "t_library", + "provider_id": "p_gen_shared", + "name": "OPAC Library API (Gen Shared)", + "features": { + "latency_ms": 350.22, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 503.36, + "gen_feat_2": 0.490142, + "gen_feat_3": 513.01 + } + }, + { + "id": "t_geocoding_gen_1", + "task_id": "t_geocoding", + "provider_id": "p_gen_shared", + "name": "Google Maps Geocoding API (Gen Shared)", + "features": { + "latency_ms": 299.52, + "cost_usd": 0.0, + "availability": 0.970921, + "gen_feat_1": 509.42, + "gen_feat_2": 0.491433, + "gen_feat_3": 503.84 + } + }, + { + "id": "t_transit_gen_1", + "task_id": "t_transit", + "provider_id": "p_gen_shared", + "name": "Google Transit API (Gen Shared)", + "features": { + "latency_ms": 457.93, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.8, + "gen_feat_2": 0.5146, + "gen_feat_3": 509.74 + } + }, + { + "id": "t_archive_gen_1", + "task_id": "t_archive", + "provider_id": "p_gen_shared", + "name": "Archive.org API (Gen Shared)", + "features": { + "latency_ms": 494.4, + "cost_usd": 0.0, + "availability": 0.973217, + "gen_feat_1": 486.21, + "gen_feat_2": 0.487758, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_books_gen_2", + "task_id": "t_books", + "provider_id": "p_unimib", + "name": "Google Books API (Gen p_unimib)", + "features": { + "latency_ms": 251.51, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.43, + "gen_feat_2": 0.49659, + "gen_feat_3": 492.56 + } + }, + { + "id": "t_books_gen_3", + "task_id": "t_books", + "provider_id": "p_archive", + "name": "Google Books API (Gen p_archive)", + "features": { + "latency_ms": 253.59, + "cost_usd": 0.0, + "availability": 0.976832, + "gen_feat_1": 498.31, + "gen_feat_2": 0.504989, + "gen_feat_3": 485.73 + } + }, + { + "id": "t_books_gen_4", + "task_id": "t_books", + "provider_id": "p_local", + "name": "Google Books API (Gen p_local)", + "features": { + "latency_ms": 253.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 496.81, + "gen_feat_2": 0.509742, + "gen_feat_3": 503.82 + } + }, + { + "id": "t_books_gen_5", + "task_id": "t_books", + "provider_id": "p_gen_1", + "name": "Google Books API (Gen p_gen_1)", + "features": { + "latency_ms": 243.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.29, + "gen_feat_2": 0.497801, + "gen_feat_3": 491.8 + } + }, + { + "id": "t_books_gen_6", + "task_id": "t_books", + "provider_id": "p_gen_2", + "name": "Google Books API (Gen p_gen_2)", + "features": { + "latency_ms": 249.33, + "cost_usd": 0.0, + "availability": 0.968324, + "gen_feat_1": 500.1, + "gen_feat_2": 0.489322, + "gen_feat_3": 486.96 + } + }, + { + "id": "t_books_gen_7", + "task_id": "t_books", + "provider_id": "p_gen_3", + "name": "Google Books API (Gen p_gen_3)", + "features": { + "latency_ms": 244.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.49, + "gen_feat_2": 0.509901, + "gen_feat_3": 510.32 + } + }, + { + "id": "t_books_gen_8", + "task_id": "t_books", + "provider_id": "p_gen_4", + "name": "Google Books API (Gen p_gen_4)", + "features": { + "latency_ms": 249.93, + "cost_usd": 0.0, + "availability": 0.984683, + "gen_feat_1": 503.61, + "gen_feat_2": 0.501017, + "gen_feat_3": 501.49 + } + }, + { + "id": "t_books_gen_9", + "task_id": "t_books", + "provider_id": "p_gen_5", + "name": "Google Books API (Gen p_gen_5)", + "features": { + "latency_ms": 252.75, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 505.53, + "gen_feat_2": 0.491572, + "gen_feat_3": 506.63 + } + }, + { + "id": "t_market_gen_2", + "task_id": "t_market", + "provider_id": "p_google", + "name": "Amazon Market API (Gen p_google)", + "features": { + "latency_ms": 390.51, + "cost_usd": 0.0, + "availability": 0.974193, + "gen_feat_1": 514.03, + "gen_feat_2": 0.504606, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_market_gen_3", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API (Gen p_amazon)", + "features": { + "latency_ms": 390.29, + "cost_usd": 0.0, + "availability": 0.964065, + "gen_feat_1": 490.39, + "gen_feat_2": 0.510618, + "gen_feat_3": 500.06 + } + }, + { + "id": "t_market_gen_4", + "task_id": "t_market", + "provider_id": "p_unimib", + "name": "Amazon Market API (Gen p_unimib)", + "features": { + "latency_ms": 403.22, + "cost_usd": 0.0, + "availability": 0.98629, + "gen_feat_1": 506.11, + "gen_feat_2": 0.504836, + "gen_feat_3": 513.95 + } + }, + { + "id": "t_market_gen_5", + "task_id": "t_market", + "provider_id": "p_archive", + "name": "Amazon Market API (Gen p_archive)", + "features": { + "latency_ms": 392.94, + "cost_usd": 0.0, + "availability": 0.963527, + "gen_feat_1": 512.48, + "gen_feat_2": 0.514296, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_market_gen_6", + "task_id": "t_market", + "provider_id": "p_local", + "name": "Amazon Market API (Gen p_local)", + "features": { + "latency_ms": 393.03, + "cost_usd": 0.0, + "availability": 0.981369, + "gen_feat_1": 488.34, + "gen_feat_2": 0.514668, + "gen_feat_3": 505.0 + } + }, + { + "id": "t_market_gen_7", + "task_id": "t_market", + "provider_id": "p_gen_1", + "name": "Amazon Market API (Gen p_gen_1)", + "features": { + "latency_ms": 411.7, + "cost_usd": 0.0, + "availability": 0.985823, + "gen_feat_1": 500.86, + "gen_feat_2": 0.497755, + "gen_feat_3": 497.03 + } + }, + { + "id": "t_market_gen_8", + "task_id": "t_market", + "provider_id": "p_gen_2", + "name": "Amazon Market API (Gen p_gen_2)", + "features": { + "latency_ms": 402.71, + "cost_usd": 0.0, + "availability": 0.991509, + "gen_feat_1": 505.13, + "gen_feat_2": 0.49775, + "gen_feat_3": 491.63 + } + }, + { + "id": "t_market_gen_9", + "task_id": "t_market", + "provider_id": "p_gen_3", + "name": "Amazon Market API (Gen p_gen_3)", + "features": { + "latency_ms": 402.55, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 510.3, + "gen_feat_2": 0.501032, + "gen_feat_3": 505.68 + } + }, + { + "id": "t_library_gen_2", + "task_id": "t_library", + "provider_id": "p_gen_4", + "name": "OPAC Library API (Gen p_gen_4)", + "features": { + "latency_ms": 345.85, + "cost_usd": 0.0, + "availability": 0.97661, + "gen_feat_1": 508.48, + "gen_feat_2": 0.509068, + "gen_feat_3": 505.91 + } + }, + { + "id": "t_library_gen_3", + "task_id": "t_library", + "provider_id": "p_gen_5", + "name": "OPAC Library API (Gen p_gen_5)", + "features": { + "latency_ms": 357.65, + "cost_usd": 0.0, + "availability": 0.995668, + "gen_feat_1": 511.52, + "gen_feat_2": 0.489245, + "gen_feat_3": 489.95 + } + }, + { + "id": "t_library_gen_4", + "task_id": "t_library", + "provider_id": "p_google", + "name": "OPAC Library API (Gen p_google)", + "features": { + "latency_ms": 347.46, + "cost_usd": 0.0, + "availability": 0.961356, + "gen_feat_1": 510.48, + "gen_feat_2": 0.509522, + "gen_feat_3": 510.51 + } + }, + { + "id": "t_library_gen_5", + "task_id": "t_library", + "provider_id": "p_amazon", + "name": "OPAC Library API (Gen p_amazon)", + "features": { + "latency_ms": 346.07, + "cost_usd": 0.0, + "availability": 0.99049, + "gen_feat_1": 510.53, + "gen_feat_2": 0.488512, + "gen_feat_3": 513.85 + } + }, + { + "id": "t_library_gen_6", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API (Gen p_unimib)", + "features": { + "latency_ms": 353.12, + "cost_usd": 0.0, + "availability": 0.966548, + "gen_feat_1": 500.27, + "gen_feat_2": 0.497436, + "gen_feat_3": 511.73 + } + }, + { + "id": "t_library_gen_7", + "task_id": "t_library", + "provider_id": "p_archive", + "name": "OPAC Library API (Gen p_archive)", + "features": { + "latency_ms": 356.85, + "cost_usd": 0.0, + "availability": 0.993546, + "gen_feat_1": 510.3, + "gen_feat_2": 0.513619, + "gen_feat_3": 511.4 + } + }, + { + "id": "t_library_gen_8", + "task_id": "t_library", + "provider_id": "p_local", + "name": "OPAC Library API (Gen p_local)", + "features": { + "latency_ms": 357.15, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.06, + "gen_feat_2": 0.487388, + "gen_feat_3": 498.18 + } + }, + { + "id": "t_library_gen_9", + "task_id": "t_library", + "provider_id": "p_gen_1", + "name": "OPAC Library API (Gen p_gen_1)", + "features": { + "latency_ms": 355.46, + "cost_usd": 0.0, + "availability": 0.970169, + "gen_feat_1": 490.3, + "gen_feat_2": 0.497807, + "gen_feat_3": 495.16 + } + }, + { + "id": "t_geocoding_gen_2", + "task_id": "t_geocoding", + "provider_id": "p_gen_2", + "name": "Google Maps Geocoding API (Gen p_gen_2)", + "features": { + "latency_ms": 293.3, + "cost_usd": 0.0, + "availability": 0.974652, + "gen_feat_1": 508.37, + "gen_feat_2": 0.500348, + "gen_feat_3": 495.48 + } + }, + { + "id": "t_geocoding_gen_3", + "task_id": "t_geocoding", + "provider_id": "p_gen_3", + "name": "Google Maps Geocoding API (Gen p_gen_3)", + "features": { + "latency_ms": 298.14, + "cost_usd": 0.0, + "availability": 0.985441, + "gen_feat_1": 501.06, + "gen_feat_2": 0.508714, + "gen_feat_3": 511.67 + } + }, + { + "id": "t_geocoding_gen_4", + "task_id": "t_geocoding", + "provider_id": "p_gen_4", + "name": "Google Maps Geocoding API (Gen p_gen_4)", + "features": { + "latency_ms": 296.31, + "cost_usd": 0.0, + "availability": 0.970937, + "gen_feat_1": 504.66, + "gen_feat_2": 0.485959, + "gen_feat_3": 506.47 + } + }, + { + "id": "t_geocoding_gen_5", + "task_id": "t_geocoding", + "provider_id": "p_gen_5", + "name": "Google Maps Geocoding API (Gen p_gen_5)", + "features": { + "latency_ms": 292.44, + "cost_usd": 0.0, + "availability": 0.970116, + "gen_feat_1": 506.54, + "gen_feat_2": 0.485388, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_geocoding_gen_6", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API (Gen p_google)", + "features": { + "latency_ms": 296.68, + "cost_usd": 0.0, + "availability": 0.979126, + "gen_feat_1": 503.49, + "gen_feat_2": 0.509299, + "gen_feat_3": 501.7 + } + }, + { + "id": "t_geocoding_gen_7", + "task_id": "t_geocoding", + "provider_id": "p_amazon", + "name": "Google Maps Geocoding API (Gen p_amazon)", + "features": { + "latency_ms": 299.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.43, + "gen_feat_2": 0.485447, + "gen_feat_3": 504.86 + } + }, + { + "id": "t_geocoding_gen_8", + "task_id": "t_geocoding", + "provider_id": "p_unimib", + "name": "Google Maps Geocoding API (Gen p_unimib)", + "features": { + "latency_ms": 291.86, + "cost_usd": 0.0, + "availability": 0.967929, + "gen_feat_1": 500.94, + "gen_feat_2": 0.487602, + "gen_feat_3": 501.12 + } + }, + { + "id": "t_geocoding_gen_9", + "task_id": "t_geocoding", + "provider_id": "p_archive", + "name": "Google Maps Geocoding API (Gen p_archive)", + "features": { + "latency_ms": 303.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.48, + "gen_feat_2": 0.494252, + "gen_feat_3": 501.53 + } + }, + { + "id": "t_transit_gen_2", + "task_id": "t_transit", + "provider_id": "p_local", + "name": "Google Transit API (Gen p_local)", + "features": { + "latency_ms": 447.81, + "cost_usd": 0.0, + "availability": 0.97876, + "gen_feat_1": 487.34, + "gen_feat_2": 0.494893, + "gen_feat_3": 492.66 + } + }, + { + "id": "t_transit_gen_3", + "task_id": "t_transit", + "provider_id": "p_gen_1", + "name": "Google Transit API (Gen p_gen_1)", + "features": { + "latency_ms": 454.73, + "cost_usd": 0.0, + "availability": 0.982378, + "gen_feat_1": 508.31, + "gen_feat_2": 0.486183, + "gen_feat_3": 501.39 + } + }, + { + "id": "t_transit_gen_4", + "task_id": "t_transit", + "provider_id": "p_gen_2", + "name": "Google Transit API (Gen p_gen_2)", + "features": { + "latency_ms": 463.1, + "cost_usd": 0.0, + "availability": 0.967212, + "gen_feat_1": 512.89, + "gen_feat_2": 0.512956, + "gen_feat_3": 495.23 + } + }, + { + "id": "t_transit_gen_5", + "task_id": "t_transit", + "provider_id": "p_gen_3", + "name": "Google Transit API (Gen p_gen_3)", + "features": { + "latency_ms": 456.23, + "cost_usd": 0.0, + "availability": 0.965992, + "gen_feat_1": 490.49, + "gen_feat_2": 0.508133, + "gen_feat_3": 504.92 + } + }, + { + "id": "t_transit_gen_6", + "task_id": "t_transit", + "provider_id": "p_gen_4", + "name": "Google Transit API (Gen p_gen_4)", + "features": { + "latency_ms": 440.18, + "cost_usd": 0.0, + "availability": 0.991733, + "gen_feat_1": 490.83, + "gen_feat_2": 0.504993, + "gen_feat_3": 492.89 + } + }, + { + "id": "t_transit_gen_7", + "task_id": "t_transit", + "provider_id": "p_gen_5", + "name": "Google Transit API (Gen p_gen_5)", + "features": { + "latency_ms": 462.92, + "cost_usd": 0.0, + "availability": 0.996902, + "gen_feat_1": 511.69, + "gen_feat_2": 0.506072, + "gen_feat_3": 487.84 + } + }, + { + "id": "t_transit_gen_8", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API (Gen p_google)", + "features": { + "latency_ms": 437.2, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 486.88, + "gen_feat_2": 0.486007, + "gen_feat_3": 512.05 + } + }, + { + "id": "t_transit_gen_9", + "task_id": "t_transit", + "provider_id": "p_amazon", + "name": "Google Transit API (Gen p_amazon)", + "features": { + "latency_ms": 454.11, + "cost_usd": 0.0, + "availability": 0.993251, + "gen_feat_1": 496.88, + "gen_feat_2": 0.494363, + "gen_feat_3": 508.7 + } + }, + { + "id": "t_archive_gen_2", + "task_id": "t_archive", + "provider_id": "p_unimib", + "name": "Archive.org API (Gen p_unimib)", + "features": { + "latency_ms": 491.38, + "cost_usd": 0.0, + "availability": 0.97419, + "gen_feat_1": 488.94, + "gen_feat_2": 0.490436, + "gen_feat_3": 502.27 + } + }, + { + "id": "t_archive_gen_3", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API (Gen p_archive)", + "features": { + "latency_ms": 493.0, + "cost_usd": 0.0, + "availability": 0.974135, + "gen_feat_1": 509.85, + "gen_feat_2": 0.501448, + "gen_feat_3": 508.14 + } + }, + { + "id": "t_archive_gen_4", + "task_id": "t_archive", + "provider_id": "p_local", + "name": "Archive.org API (Gen p_local)", + "features": { + "latency_ms": 506.7, + "cost_usd": 0.0, + "availability": 0.950007, + "gen_feat_1": 485.3, + "gen_feat_2": 0.506074, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_archive_gen_5", + "task_id": "t_archive", + "provider_id": "p_gen_1", + "name": "Archive.org API (Gen p_gen_1)", + "features": { + "latency_ms": 489.16, + "cost_usd": 0.0, + "availability": 0.997048, + "gen_feat_1": 498.8, + "gen_feat_2": 0.513697, + "gen_feat_3": 499.99 + } + }, + { + "id": "t_archive_gen_6", + "task_id": "t_archive", + "provider_id": "p_gen_2", + "name": "Archive.org API (Gen p_gen_2)", + "features": { + "latency_ms": 490.4, + "cost_usd": 0.0, + "availability": 0.989264, + "gen_feat_1": 499.32, + "gen_feat_2": 0.492021, + "gen_feat_3": 511.64 + } + }, + { + "id": "t_archive_gen_7", + "task_id": "t_archive", + "provider_id": "p_gen_3", + "name": "Archive.org API (Gen p_gen_3)", + "features": { + "latency_ms": 493.82, + "cost_usd": 0.0, + "availability": 0.963902, + "gen_feat_1": 513.54, + "gen_feat_2": 0.514704, + "gen_feat_3": 488.6 + } + }, + { + "id": "t_archive_gen_8", + "task_id": "t_archive", + "provider_id": "p_gen_4", + "name": "Archive.org API (Gen p_gen_4)", + "features": { + "latency_ms": 501.92, + "cost_usd": 0.0, + "availability": 0.987176, + "gen_feat_1": 487.31, + "gen_feat_2": 0.5052, + "gen_feat_3": 512.55 + } + }, + { + "id": "t_archive_gen_9", + "task_id": "t_archive", + "provider_id": "p_gen_5", + "name": "Archive.org API (Gen p_gen_5)", + "features": { + "latency_ms": 497.11, + "cost_usd": 0.0, + "availability": 0.959066, + "gen_feat_1": 489.18, + "gen_feat_2": 0.487091, + "gen_feat_3": 488.33 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_books", + "kind": "TASK", + "task_id": "t_books" + }, + { + "id": "n_parallel_options", + "kind": "AND", + "children": [ + { + "id": "n_amazon", + "kind": "TASK", + "task_id": "t_market" + }, + { + "id": "n_library_trip", + "kind": "SEQ", + "children": [ + { + "id": "n_opac", + "kind": "TASK", + "task_id": "t_library" + }, + { + "id": "n_geocode", + "kind": "TASK", + "task_id": "t_geocoding" + }, + { + "id": "n_transit", + "kind": "TASK", + "task_id": "t_transit" + } + ] + }, + { + "id": "n_archive", + "kind": "TASK", + "task_id": "t_archive" + } + ] + }, + { + "id": "n_report", + "kind": "ELEMENT", + "description": "Assemble final textbook access report" + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MANY", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1357.94, + "hard": false + }, + { + "id": "gen_c_local_t_archive_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_archive" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_books", + "t_geocoding" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_archive", + "t_books" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/cremaschi2018-textbook-access_mono_one_hard.json b/experimentation/instances/cremaschi2018-textbook-access_mono_one_hard.json new file mode 100644 index 0000000..72cce56 --- /dev/null +++ b/experimentation/instances/cremaschi2018-textbook-access_mono_one_hard.json @@ -0,0 +1,1192 @@ +{ + "metadata": { + "id": "cremaschi2018-textbook-access_mono_one_hard", + "name": "Book info retrieval (Cremaschi et al. 2018) [mono_one, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "QoS-aware instance derived from the running example in 'A Practical Approach to Services Composition Through Light Semantic Descriptions' (ESOCC 2018). QoS values are illustrative placeholders.", + "paper": { + "title": "A Practical Approach to Services Composition Through Light Semantic Descriptions", + "authors": "M. Cremaschi et al.", + "year": 2018, + "doi": "10.1007/978-3-319-99819-0_10" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Monetary cost per execution", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10 + } + }, + { + "id": "availability", + "name": "Service availability", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_google", + "name": "Google" + }, + { + "id": "p_amazon", + "name": "Amazon" + }, + { + "id": "p_unimib", + "name": "University of Milan - Bicocca (OPAC library)" + }, + { + "id": "p_archive", + "name": "Archive.org" + }, + { + "id": "p_local", + "name": "Local Application" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_books", + "name": "Retrieve book metadata from title (ISBN/author/title)" + }, + { + "id": "t_market", + "name": "Check e-commerce availability/price by ISBN" + }, + { + "id": "t_library", + "name": "Check library availability and retrieve library address" + }, + { + "id": "t_geocoding", + "name": "Geocode library address into coordinates" + }, + { + "id": "t_transit", + "name": "Retrieve public transport options to the library" + }, + { + "id": "t_archive", + "name": "Check free eBook availability (Archive.org)" + } + ], + "candidates": [ + { + "id": "c_google_books_api", + "task_id": "t_books", + "provider_id": "p_google", + "name": "Google Books API", + "features": { + "latency_ms": 250, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_amazon_market_api", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API", + "features": { + "latency_ms": 400, + "cost_usd": 0.001, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_opac_library_api", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API", + "features": { + "latency_ms": 350, + "cost_usd": 0.0001, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_geocoding_api", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API", + "features": { + "latency_ms": 300, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_transit_api", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API", + "features": { + "latency_ms": 450, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_archive_api", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API", + "features": { + "latency_ms": 500, + "cost_usd": 0.0001, + "availability": 0.97, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_books_gen_1", + "task_id": "t_books", + "provider_id": "p_gen_shared", + "name": "Google Books API (Gen Shared)", + "features": { + "latency_ms": 250.27, + "cost_usd": 0.0, + "availability": 0.970656, + "gen_feat_1": 507.35, + "gen_feat_2": 0.498346, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_market_gen_1", + "task_id": "t_market", + "provider_id": "p_gen_shared", + "name": "Amazon Market API (Gen Shared)", + "features": { + "latency_ms": 410.3, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.37, + "gen_feat_2": 0.4873, + "gen_feat_3": 499.78 + } + }, + { + "id": "t_library_gen_1", + "task_id": "t_library", + "provider_id": "p_gen_shared", + "name": "OPAC Library API (Gen Shared)", + "features": { + "latency_ms": 350.22, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 503.36, + "gen_feat_2": 0.490142, + "gen_feat_3": 513.01 + } + }, + { + "id": "t_geocoding_gen_1", + "task_id": "t_geocoding", + "provider_id": "p_gen_shared", + "name": "Google Maps Geocoding API (Gen Shared)", + "features": { + "latency_ms": 299.52, + "cost_usd": 0.0, + "availability": 0.970921, + "gen_feat_1": 509.42, + "gen_feat_2": 0.491433, + "gen_feat_3": 503.84 + } + }, + { + "id": "t_transit_gen_1", + "task_id": "t_transit", + "provider_id": "p_gen_shared", + "name": "Google Transit API (Gen Shared)", + "features": { + "latency_ms": 457.93, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.8, + "gen_feat_2": 0.5146, + "gen_feat_3": 509.74 + } + }, + { + "id": "t_archive_gen_1", + "task_id": "t_archive", + "provider_id": "p_gen_shared", + "name": "Archive.org API (Gen Shared)", + "features": { + "latency_ms": 494.4, + "cost_usd": 0.0, + "availability": 0.973217, + "gen_feat_1": 486.21, + "gen_feat_2": 0.487758, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_books_gen_2", + "task_id": "t_books", + "provider_id": "p_unimib", + "name": "Google Books API (Gen p_unimib)", + "features": { + "latency_ms": 251.51, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.43, + "gen_feat_2": 0.49659, + "gen_feat_3": 492.56 + } + }, + { + "id": "t_books_gen_3", + "task_id": "t_books", + "provider_id": "p_archive", + "name": "Google Books API (Gen p_archive)", + "features": { + "latency_ms": 253.59, + "cost_usd": 0.0, + "availability": 0.976832, + "gen_feat_1": 498.31, + "gen_feat_2": 0.504989, + "gen_feat_3": 485.73 + } + }, + { + "id": "t_books_gen_4", + "task_id": "t_books", + "provider_id": "p_local", + "name": "Google Books API (Gen p_local)", + "features": { + "latency_ms": 253.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 496.81, + "gen_feat_2": 0.509742, + "gen_feat_3": 503.82 + } + }, + { + "id": "t_books_gen_5", + "task_id": "t_books", + "provider_id": "p_gen_1", + "name": "Google Books API (Gen p_gen_1)", + "features": { + "latency_ms": 243.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.29, + "gen_feat_2": 0.497801, + "gen_feat_3": 491.8 + } + }, + { + "id": "t_books_gen_6", + "task_id": "t_books", + "provider_id": "p_gen_2", + "name": "Google Books API (Gen p_gen_2)", + "features": { + "latency_ms": 249.33, + "cost_usd": 0.0, + "availability": 0.968324, + "gen_feat_1": 500.1, + "gen_feat_2": 0.489322, + "gen_feat_3": 486.96 + } + }, + { + "id": "t_books_gen_7", + "task_id": "t_books", + "provider_id": "p_gen_3", + "name": "Google Books API (Gen p_gen_3)", + "features": { + "latency_ms": 244.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.49, + "gen_feat_2": 0.509901, + "gen_feat_3": 510.32 + } + }, + { + "id": "t_books_gen_8", + "task_id": "t_books", + "provider_id": "p_gen_4", + "name": "Google Books API (Gen p_gen_4)", + "features": { + "latency_ms": 249.93, + "cost_usd": 0.0, + "availability": 0.984683, + "gen_feat_1": 503.61, + "gen_feat_2": 0.501017, + "gen_feat_3": 501.49 + } + }, + { + "id": "t_books_gen_9", + "task_id": "t_books", + "provider_id": "p_gen_5", + "name": "Google Books API (Gen p_gen_5)", + "features": { + "latency_ms": 252.75, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 505.53, + "gen_feat_2": 0.491572, + "gen_feat_3": 506.63 + } + }, + { + "id": "t_market_gen_2", + "task_id": "t_market", + "provider_id": "p_google", + "name": "Amazon Market API (Gen p_google)", + "features": { + "latency_ms": 390.51, + "cost_usd": 0.0, + "availability": 0.974193, + "gen_feat_1": 514.03, + "gen_feat_2": 0.504606, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_market_gen_3", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API (Gen p_amazon)", + "features": { + "latency_ms": 390.29, + "cost_usd": 0.0, + "availability": 0.964065, + "gen_feat_1": 490.39, + "gen_feat_2": 0.510618, + "gen_feat_3": 500.06 + } + }, + { + "id": "t_market_gen_4", + "task_id": "t_market", + "provider_id": "p_unimib", + "name": "Amazon Market API (Gen p_unimib)", + "features": { + "latency_ms": 403.22, + "cost_usd": 0.0, + "availability": 0.98629, + "gen_feat_1": 506.11, + "gen_feat_2": 0.504836, + "gen_feat_3": 513.95 + } + }, + { + "id": "t_market_gen_5", + "task_id": "t_market", + "provider_id": "p_archive", + "name": "Amazon Market API (Gen p_archive)", + "features": { + "latency_ms": 392.94, + "cost_usd": 0.0, + "availability": 0.963527, + "gen_feat_1": 512.48, + "gen_feat_2": 0.514296, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_market_gen_6", + "task_id": "t_market", + "provider_id": "p_local", + "name": "Amazon Market API (Gen p_local)", + "features": { + "latency_ms": 393.03, + "cost_usd": 0.0, + "availability": 0.981369, + "gen_feat_1": 488.34, + "gen_feat_2": 0.514668, + "gen_feat_3": 505.0 + } + }, + { + "id": "t_market_gen_7", + "task_id": "t_market", + "provider_id": "p_gen_1", + "name": "Amazon Market API (Gen p_gen_1)", + "features": { + "latency_ms": 411.7, + "cost_usd": 0.0, + "availability": 0.985823, + "gen_feat_1": 500.86, + "gen_feat_2": 0.497755, + "gen_feat_3": 497.03 + } + }, + { + "id": "t_market_gen_8", + "task_id": "t_market", + "provider_id": "p_gen_2", + "name": "Amazon Market API (Gen p_gen_2)", + "features": { + "latency_ms": 402.71, + "cost_usd": 0.0, + "availability": 0.991509, + "gen_feat_1": 505.13, + "gen_feat_2": 0.49775, + "gen_feat_3": 491.63 + } + }, + { + "id": "t_market_gen_9", + "task_id": "t_market", + "provider_id": "p_gen_3", + "name": "Amazon Market API (Gen p_gen_3)", + "features": { + "latency_ms": 402.55, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 510.3, + "gen_feat_2": 0.501032, + "gen_feat_3": 505.68 + } + }, + { + "id": "t_library_gen_2", + "task_id": "t_library", + "provider_id": "p_gen_4", + "name": "OPAC Library API (Gen p_gen_4)", + "features": { + "latency_ms": 345.85, + "cost_usd": 0.0, + "availability": 0.97661, + "gen_feat_1": 508.48, + "gen_feat_2": 0.509068, + "gen_feat_3": 505.91 + } + }, + { + "id": "t_library_gen_3", + "task_id": "t_library", + "provider_id": "p_gen_5", + "name": "OPAC Library API (Gen p_gen_5)", + "features": { + "latency_ms": 357.65, + "cost_usd": 0.0, + "availability": 0.995668, + "gen_feat_1": 511.52, + "gen_feat_2": 0.489245, + "gen_feat_3": 489.95 + } + }, + { + "id": "t_library_gen_4", + "task_id": "t_library", + "provider_id": "p_google", + "name": "OPAC Library API (Gen p_google)", + "features": { + "latency_ms": 347.46, + "cost_usd": 0.0, + "availability": 0.961356, + "gen_feat_1": 510.48, + "gen_feat_2": 0.509522, + "gen_feat_3": 510.51 + } + }, + { + "id": "t_library_gen_5", + "task_id": "t_library", + "provider_id": "p_amazon", + "name": "OPAC Library API (Gen p_amazon)", + "features": { + "latency_ms": 346.07, + "cost_usd": 0.0, + "availability": 0.99049, + "gen_feat_1": 510.53, + "gen_feat_2": 0.488512, + "gen_feat_3": 513.85 + } + }, + { + "id": "t_library_gen_6", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API (Gen p_unimib)", + "features": { + "latency_ms": 353.12, + "cost_usd": 0.0, + "availability": 0.966548, + "gen_feat_1": 500.27, + "gen_feat_2": 0.497436, + "gen_feat_3": 511.73 + } + }, + { + "id": "t_library_gen_7", + "task_id": "t_library", + "provider_id": "p_archive", + "name": "OPAC Library API (Gen p_archive)", + "features": { + "latency_ms": 356.85, + "cost_usd": 0.0, + "availability": 0.993546, + "gen_feat_1": 510.3, + "gen_feat_2": 0.513619, + "gen_feat_3": 511.4 + } + }, + { + "id": "t_library_gen_8", + "task_id": "t_library", + "provider_id": "p_local", + "name": "OPAC Library API (Gen p_local)", + "features": { + "latency_ms": 357.15, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.06, + "gen_feat_2": 0.487388, + "gen_feat_3": 498.18 + } + }, + { + "id": "t_library_gen_9", + "task_id": "t_library", + "provider_id": "p_gen_1", + "name": "OPAC Library API (Gen p_gen_1)", + "features": { + "latency_ms": 355.46, + "cost_usd": 0.0, + "availability": 0.970169, + "gen_feat_1": 490.3, + "gen_feat_2": 0.497807, + "gen_feat_3": 495.16 + } + }, + { + "id": "t_geocoding_gen_2", + "task_id": "t_geocoding", + "provider_id": "p_gen_2", + "name": "Google Maps Geocoding API (Gen p_gen_2)", + "features": { + "latency_ms": 293.3, + "cost_usd": 0.0, + "availability": 0.974652, + "gen_feat_1": 508.37, + "gen_feat_2": 0.500348, + "gen_feat_3": 495.48 + } + }, + { + "id": "t_geocoding_gen_3", + "task_id": "t_geocoding", + "provider_id": "p_gen_3", + "name": "Google Maps Geocoding API (Gen p_gen_3)", + "features": { + "latency_ms": 298.14, + "cost_usd": 0.0, + "availability": 0.985441, + "gen_feat_1": 501.06, + "gen_feat_2": 0.508714, + "gen_feat_3": 511.67 + } + }, + { + "id": "t_geocoding_gen_4", + "task_id": "t_geocoding", + "provider_id": "p_gen_4", + "name": "Google Maps Geocoding API (Gen p_gen_4)", + "features": { + "latency_ms": 296.31, + "cost_usd": 0.0, + "availability": 0.970937, + "gen_feat_1": 504.66, + "gen_feat_2": 0.485959, + "gen_feat_3": 506.47 + } + }, + { + "id": "t_geocoding_gen_5", + "task_id": "t_geocoding", + "provider_id": "p_gen_5", + "name": "Google Maps Geocoding API (Gen p_gen_5)", + "features": { + "latency_ms": 292.44, + "cost_usd": 0.0, + "availability": 0.970116, + "gen_feat_1": 506.54, + "gen_feat_2": 0.485388, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_geocoding_gen_6", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API (Gen p_google)", + "features": { + "latency_ms": 296.68, + "cost_usd": 0.0, + "availability": 0.979126, + "gen_feat_1": 503.49, + "gen_feat_2": 0.509299, + "gen_feat_3": 501.7 + } + }, + { + "id": "t_geocoding_gen_7", + "task_id": "t_geocoding", + "provider_id": "p_amazon", + "name": "Google Maps Geocoding API (Gen p_amazon)", + "features": { + "latency_ms": 299.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.43, + "gen_feat_2": 0.485447, + "gen_feat_3": 504.86 + } + }, + { + "id": "t_geocoding_gen_8", + "task_id": "t_geocoding", + "provider_id": "p_unimib", + "name": "Google Maps Geocoding API (Gen p_unimib)", + "features": { + "latency_ms": 291.86, + "cost_usd": 0.0, + "availability": 0.967929, + "gen_feat_1": 500.94, + "gen_feat_2": 0.487602, + "gen_feat_3": 501.12 + } + }, + { + "id": "t_geocoding_gen_9", + "task_id": "t_geocoding", + "provider_id": "p_archive", + "name": "Google Maps Geocoding API (Gen p_archive)", + "features": { + "latency_ms": 303.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.48, + "gen_feat_2": 0.494252, + "gen_feat_3": 501.53 + } + }, + { + "id": "t_transit_gen_2", + "task_id": "t_transit", + "provider_id": "p_local", + "name": "Google Transit API (Gen p_local)", + "features": { + "latency_ms": 447.81, + "cost_usd": 0.0, + "availability": 0.97876, + "gen_feat_1": 487.34, + "gen_feat_2": 0.494893, + "gen_feat_3": 492.66 + } + }, + { + "id": "t_transit_gen_3", + "task_id": "t_transit", + "provider_id": "p_gen_1", + "name": "Google Transit API (Gen p_gen_1)", + "features": { + "latency_ms": 454.73, + "cost_usd": 0.0, + "availability": 0.982378, + "gen_feat_1": 508.31, + "gen_feat_2": 0.486183, + "gen_feat_3": 501.39 + } + }, + { + "id": "t_transit_gen_4", + "task_id": "t_transit", + "provider_id": "p_gen_2", + "name": "Google Transit API (Gen p_gen_2)", + "features": { + "latency_ms": 463.1, + "cost_usd": 0.0, + "availability": 0.967212, + "gen_feat_1": 512.89, + "gen_feat_2": 0.512956, + "gen_feat_3": 495.23 + } + }, + { + "id": "t_transit_gen_5", + "task_id": "t_transit", + "provider_id": "p_gen_3", + "name": "Google Transit API (Gen p_gen_3)", + "features": { + "latency_ms": 456.23, + "cost_usd": 0.0, + "availability": 0.965992, + "gen_feat_1": 490.49, + "gen_feat_2": 0.508133, + "gen_feat_3": 504.92 + } + }, + { + "id": "t_transit_gen_6", + "task_id": "t_transit", + "provider_id": "p_gen_4", + "name": "Google Transit API (Gen p_gen_4)", + "features": { + "latency_ms": 440.18, + "cost_usd": 0.0, + "availability": 0.991733, + "gen_feat_1": 490.83, + "gen_feat_2": 0.504993, + "gen_feat_3": 492.89 + } + }, + { + "id": "t_transit_gen_7", + "task_id": "t_transit", + "provider_id": "p_gen_5", + "name": "Google Transit API (Gen p_gen_5)", + "features": { + "latency_ms": 462.92, + "cost_usd": 0.0, + "availability": 0.996902, + "gen_feat_1": 511.69, + "gen_feat_2": 0.506072, + "gen_feat_3": 487.84 + } + }, + { + "id": "t_transit_gen_8", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API (Gen p_google)", + "features": { + "latency_ms": 437.2, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 486.88, + "gen_feat_2": 0.486007, + "gen_feat_3": 512.05 + } + }, + { + "id": "t_transit_gen_9", + "task_id": "t_transit", + "provider_id": "p_amazon", + "name": "Google Transit API (Gen p_amazon)", + "features": { + "latency_ms": 454.11, + "cost_usd": 0.0, + "availability": 0.993251, + "gen_feat_1": 496.88, + "gen_feat_2": 0.494363, + "gen_feat_3": 508.7 + } + }, + { + "id": "t_archive_gen_2", + "task_id": "t_archive", + "provider_id": "p_unimib", + "name": "Archive.org API (Gen p_unimib)", + "features": { + "latency_ms": 491.38, + "cost_usd": 0.0, + "availability": 0.97419, + "gen_feat_1": 488.94, + "gen_feat_2": 0.490436, + "gen_feat_3": 502.27 + } + }, + { + "id": "t_archive_gen_3", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API (Gen p_archive)", + "features": { + "latency_ms": 493.0, + "cost_usd": 0.0, + "availability": 0.974135, + "gen_feat_1": 509.85, + "gen_feat_2": 0.501448, + "gen_feat_3": 508.14 + } + }, + { + "id": "t_archive_gen_4", + "task_id": "t_archive", + "provider_id": "p_local", + "name": "Archive.org API (Gen p_local)", + "features": { + "latency_ms": 506.7, + "cost_usd": 0.0, + "availability": 0.950007, + "gen_feat_1": 485.3, + "gen_feat_2": 0.506074, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_archive_gen_5", + "task_id": "t_archive", + "provider_id": "p_gen_1", + "name": "Archive.org API (Gen p_gen_1)", + "features": { + "latency_ms": 489.16, + "cost_usd": 0.0, + "availability": 0.997048, + "gen_feat_1": 498.8, + "gen_feat_2": 0.513697, + "gen_feat_3": 499.99 + } + }, + { + "id": "t_archive_gen_6", + "task_id": "t_archive", + "provider_id": "p_gen_2", + "name": "Archive.org API (Gen p_gen_2)", + "features": { + "latency_ms": 490.4, + "cost_usd": 0.0, + "availability": 0.989264, + "gen_feat_1": 499.32, + "gen_feat_2": 0.492021, + "gen_feat_3": 511.64 + } + }, + { + "id": "t_archive_gen_7", + "task_id": "t_archive", + "provider_id": "p_gen_3", + "name": "Archive.org API (Gen p_gen_3)", + "features": { + "latency_ms": 493.82, + "cost_usd": 0.0, + "availability": 0.963902, + "gen_feat_1": 513.54, + "gen_feat_2": 0.514704, + "gen_feat_3": 488.6 + } + }, + { + "id": "t_archive_gen_8", + "task_id": "t_archive", + "provider_id": "p_gen_4", + "name": "Archive.org API (Gen p_gen_4)", + "features": { + "latency_ms": 501.92, + "cost_usd": 0.0, + "availability": 0.987176, + "gen_feat_1": 487.31, + "gen_feat_2": 0.5052, + "gen_feat_3": 512.55 + } + }, + { + "id": "t_archive_gen_9", + "task_id": "t_archive", + "provider_id": "p_gen_5", + "name": "Archive.org API (Gen p_gen_5)", + "features": { + "latency_ms": 497.11, + "cost_usd": 0.0, + "availability": 0.959066, + "gen_feat_1": 489.18, + "gen_feat_2": 0.487091, + "gen_feat_3": 488.33 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_books", + "kind": "TASK", + "task_id": "t_books" + }, + { + "id": "n_parallel_options", + "kind": "AND", + "children": [ + { + "id": "n_amazon", + "kind": "TASK", + "task_id": "t_market" + }, + { + "id": "n_library_trip", + "kind": "SEQ", + "children": [ + { + "id": "n_opac", + "kind": "TASK", + "task_id": "t_library" + }, + { + "id": "n_geocode", + "kind": "TASK", + "task_id": "t_geocoding" + }, + { + "id": "n_transit", + "kind": "TASK", + "task_id": "t_transit" + } + ] + }, + { + "id": "n_archive", + "kind": "TASK", + "task_id": "t_archive" + } + ] + }, + { + "id": "n_report", + "kind": "ELEMENT", + "description": "Assemble final textbook access report" + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "availability" + ], + "weights": { + "availability": 1.0 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1357.94, + "hard": true + }, + { + "id": "gen_c_local_t_archive_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_archive" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_books", + "t_geocoding" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_archive", + "t_books" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/cremaschi2018-textbook-access_mono_one_soft.json b/experimentation/instances/cremaschi2018-textbook-access_mono_one_soft.json new file mode 100644 index 0000000..c75a901 --- /dev/null +++ b/experimentation/instances/cremaschi2018-textbook-access_mono_one_soft.json @@ -0,0 +1,1192 @@ +{ + "metadata": { + "id": "cremaschi2018-textbook-access_mono_one_soft", + "name": "Book info retrieval (Cremaschi et al. 2018) [mono_one, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "QoS-aware instance derived from the running example in 'A Practical Approach to Services Composition Through Light Semantic Descriptions' (ESOCC 2018). QoS values are illustrative placeholders.", + "paper": { + "title": "A Practical Approach to Services Composition Through Light Semantic Descriptions", + "authors": "M. Cremaschi et al.", + "year": 2018, + "doi": "10.1007/978-3-319-99819-0_10" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Monetary cost per execution", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10 + } + }, + { + "id": "availability", + "name": "Service availability", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_google", + "name": "Google" + }, + { + "id": "p_amazon", + "name": "Amazon" + }, + { + "id": "p_unimib", + "name": "University of Milan - Bicocca (OPAC library)" + }, + { + "id": "p_archive", + "name": "Archive.org" + }, + { + "id": "p_local", + "name": "Local Application" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_books", + "name": "Retrieve book metadata from title (ISBN/author/title)" + }, + { + "id": "t_market", + "name": "Check e-commerce availability/price by ISBN" + }, + { + "id": "t_library", + "name": "Check library availability and retrieve library address" + }, + { + "id": "t_geocoding", + "name": "Geocode library address into coordinates" + }, + { + "id": "t_transit", + "name": "Retrieve public transport options to the library" + }, + { + "id": "t_archive", + "name": "Check free eBook availability (Archive.org)" + } + ], + "candidates": [ + { + "id": "c_google_books_api", + "task_id": "t_books", + "provider_id": "p_google", + "name": "Google Books API", + "features": { + "latency_ms": 250, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_amazon_market_api", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API", + "features": { + "latency_ms": 400, + "cost_usd": 0.001, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_opac_library_api", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API", + "features": { + "latency_ms": 350, + "cost_usd": 0.0001, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_geocoding_api", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API", + "features": { + "latency_ms": 300, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_transit_api", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API", + "features": { + "latency_ms": 450, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_archive_api", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API", + "features": { + "latency_ms": 500, + "cost_usd": 0.0001, + "availability": 0.97, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_books_gen_1", + "task_id": "t_books", + "provider_id": "p_gen_shared", + "name": "Google Books API (Gen Shared)", + "features": { + "latency_ms": 250.27, + "cost_usd": 0.0, + "availability": 0.970656, + "gen_feat_1": 507.35, + "gen_feat_2": 0.498346, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_market_gen_1", + "task_id": "t_market", + "provider_id": "p_gen_shared", + "name": "Amazon Market API (Gen Shared)", + "features": { + "latency_ms": 410.3, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.37, + "gen_feat_2": 0.4873, + "gen_feat_3": 499.78 + } + }, + { + "id": "t_library_gen_1", + "task_id": "t_library", + "provider_id": "p_gen_shared", + "name": "OPAC Library API (Gen Shared)", + "features": { + "latency_ms": 350.22, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 503.36, + "gen_feat_2": 0.490142, + "gen_feat_3": 513.01 + } + }, + { + "id": "t_geocoding_gen_1", + "task_id": "t_geocoding", + "provider_id": "p_gen_shared", + "name": "Google Maps Geocoding API (Gen Shared)", + "features": { + "latency_ms": 299.52, + "cost_usd": 0.0, + "availability": 0.970921, + "gen_feat_1": 509.42, + "gen_feat_2": 0.491433, + "gen_feat_3": 503.84 + } + }, + { + "id": "t_transit_gen_1", + "task_id": "t_transit", + "provider_id": "p_gen_shared", + "name": "Google Transit API (Gen Shared)", + "features": { + "latency_ms": 457.93, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.8, + "gen_feat_2": 0.5146, + "gen_feat_3": 509.74 + } + }, + { + "id": "t_archive_gen_1", + "task_id": "t_archive", + "provider_id": "p_gen_shared", + "name": "Archive.org API (Gen Shared)", + "features": { + "latency_ms": 494.4, + "cost_usd": 0.0, + "availability": 0.973217, + "gen_feat_1": 486.21, + "gen_feat_2": 0.487758, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_books_gen_2", + "task_id": "t_books", + "provider_id": "p_unimib", + "name": "Google Books API (Gen p_unimib)", + "features": { + "latency_ms": 251.51, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.43, + "gen_feat_2": 0.49659, + "gen_feat_3": 492.56 + } + }, + { + "id": "t_books_gen_3", + "task_id": "t_books", + "provider_id": "p_archive", + "name": "Google Books API (Gen p_archive)", + "features": { + "latency_ms": 253.59, + "cost_usd": 0.0, + "availability": 0.976832, + "gen_feat_1": 498.31, + "gen_feat_2": 0.504989, + "gen_feat_3": 485.73 + } + }, + { + "id": "t_books_gen_4", + "task_id": "t_books", + "provider_id": "p_local", + "name": "Google Books API (Gen p_local)", + "features": { + "latency_ms": 253.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 496.81, + "gen_feat_2": 0.509742, + "gen_feat_3": 503.82 + } + }, + { + "id": "t_books_gen_5", + "task_id": "t_books", + "provider_id": "p_gen_1", + "name": "Google Books API (Gen p_gen_1)", + "features": { + "latency_ms": 243.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.29, + "gen_feat_2": 0.497801, + "gen_feat_3": 491.8 + } + }, + { + "id": "t_books_gen_6", + "task_id": "t_books", + "provider_id": "p_gen_2", + "name": "Google Books API (Gen p_gen_2)", + "features": { + "latency_ms": 249.33, + "cost_usd": 0.0, + "availability": 0.968324, + "gen_feat_1": 500.1, + "gen_feat_2": 0.489322, + "gen_feat_3": 486.96 + } + }, + { + "id": "t_books_gen_7", + "task_id": "t_books", + "provider_id": "p_gen_3", + "name": "Google Books API (Gen p_gen_3)", + "features": { + "latency_ms": 244.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.49, + "gen_feat_2": 0.509901, + "gen_feat_3": 510.32 + } + }, + { + "id": "t_books_gen_8", + "task_id": "t_books", + "provider_id": "p_gen_4", + "name": "Google Books API (Gen p_gen_4)", + "features": { + "latency_ms": 249.93, + "cost_usd": 0.0, + "availability": 0.984683, + "gen_feat_1": 503.61, + "gen_feat_2": 0.501017, + "gen_feat_3": 501.49 + } + }, + { + "id": "t_books_gen_9", + "task_id": "t_books", + "provider_id": "p_gen_5", + "name": "Google Books API (Gen p_gen_5)", + "features": { + "latency_ms": 252.75, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 505.53, + "gen_feat_2": 0.491572, + "gen_feat_3": 506.63 + } + }, + { + "id": "t_market_gen_2", + "task_id": "t_market", + "provider_id": "p_google", + "name": "Amazon Market API (Gen p_google)", + "features": { + "latency_ms": 390.51, + "cost_usd": 0.0, + "availability": 0.974193, + "gen_feat_1": 514.03, + "gen_feat_2": 0.504606, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_market_gen_3", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API (Gen p_amazon)", + "features": { + "latency_ms": 390.29, + "cost_usd": 0.0, + "availability": 0.964065, + "gen_feat_1": 490.39, + "gen_feat_2": 0.510618, + "gen_feat_3": 500.06 + } + }, + { + "id": "t_market_gen_4", + "task_id": "t_market", + "provider_id": "p_unimib", + "name": "Amazon Market API (Gen p_unimib)", + "features": { + "latency_ms": 403.22, + "cost_usd": 0.0, + "availability": 0.98629, + "gen_feat_1": 506.11, + "gen_feat_2": 0.504836, + "gen_feat_3": 513.95 + } + }, + { + "id": "t_market_gen_5", + "task_id": "t_market", + "provider_id": "p_archive", + "name": "Amazon Market API (Gen p_archive)", + "features": { + "latency_ms": 392.94, + "cost_usd": 0.0, + "availability": 0.963527, + "gen_feat_1": 512.48, + "gen_feat_2": 0.514296, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_market_gen_6", + "task_id": "t_market", + "provider_id": "p_local", + "name": "Amazon Market API (Gen p_local)", + "features": { + "latency_ms": 393.03, + "cost_usd": 0.0, + "availability": 0.981369, + "gen_feat_1": 488.34, + "gen_feat_2": 0.514668, + "gen_feat_3": 505.0 + } + }, + { + "id": "t_market_gen_7", + "task_id": "t_market", + "provider_id": "p_gen_1", + "name": "Amazon Market API (Gen p_gen_1)", + "features": { + "latency_ms": 411.7, + "cost_usd": 0.0, + "availability": 0.985823, + "gen_feat_1": 500.86, + "gen_feat_2": 0.497755, + "gen_feat_3": 497.03 + } + }, + { + "id": "t_market_gen_8", + "task_id": "t_market", + "provider_id": "p_gen_2", + "name": "Amazon Market API (Gen p_gen_2)", + "features": { + "latency_ms": 402.71, + "cost_usd": 0.0, + "availability": 0.991509, + "gen_feat_1": 505.13, + "gen_feat_2": 0.49775, + "gen_feat_3": 491.63 + } + }, + { + "id": "t_market_gen_9", + "task_id": "t_market", + "provider_id": "p_gen_3", + "name": "Amazon Market API (Gen p_gen_3)", + "features": { + "latency_ms": 402.55, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 510.3, + "gen_feat_2": 0.501032, + "gen_feat_3": 505.68 + } + }, + { + "id": "t_library_gen_2", + "task_id": "t_library", + "provider_id": "p_gen_4", + "name": "OPAC Library API (Gen p_gen_4)", + "features": { + "latency_ms": 345.85, + "cost_usd": 0.0, + "availability": 0.97661, + "gen_feat_1": 508.48, + "gen_feat_2": 0.509068, + "gen_feat_3": 505.91 + } + }, + { + "id": "t_library_gen_3", + "task_id": "t_library", + "provider_id": "p_gen_5", + "name": "OPAC Library API (Gen p_gen_5)", + "features": { + "latency_ms": 357.65, + "cost_usd": 0.0, + "availability": 0.995668, + "gen_feat_1": 511.52, + "gen_feat_2": 0.489245, + "gen_feat_3": 489.95 + } + }, + { + "id": "t_library_gen_4", + "task_id": "t_library", + "provider_id": "p_google", + "name": "OPAC Library API (Gen p_google)", + "features": { + "latency_ms": 347.46, + "cost_usd": 0.0, + "availability": 0.961356, + "gen_feat_1": 510.48, + "gen_feat_2": 0.509522, + "gen_feat_3": 510.51 + } + }, + { + "id": "t_library_gen_5", + "task_id": "t_library", + "provider_id": "p_amazon", + "name": "OPAC Library API (Gen p_amazon)", + "features": { + "latency_ms": 346.07, + "cost_usd": 0.0, + "availability": 0.99049, + "gen_feat_1": 510.53, + "gen_feat_2": 0.488512, + "gen_feat_3": 513.85 + } + }, + { + "id": "t_library_gen_6", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API (Gen p_unimib)", + "features": { + "latency_ms": 353.12, + "cost_usd": 0.0, + "availability": 0.966548, + "gen_feat_1": 500.27, + "gen_feat_2": 0.497436, + "gen_feat_3": 511.73 + } + }, + { + "id": "t_library_gen_7", + "task_id": "t_library", + "provider_id": "p_archive", + "name": "OPAC Library API (Gen p_archive)", + "features": { + "latency_ms": 356.85, + "cost_usd": 0.0, + "availability": 0.993546, + "gen_feat_1": 510.3, + "gen_feat_2": 0.513619, + "gen_feat_3": 511.4 + } + }, + { + "id": "t_library_gen_8", + "task_id": "t_library", + "provider_id": "p_local", + "name": "OPAC Library API (Gen p_local)", + "features": { + "latency_ms": 357.15, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.06, + "gen_feat_2": 0.487388, + "gen_feat_3": 498.18 + } + }, + { + "id": "t_library_gen_9", + "task_id": "t_library", + "provider_id": "p_gen_1", + "name": "OPAC Library API (Gen p_gen_1)", + "features": { + "latency_ms": 355.46, + "cost_usd": 0.0, + "availability": 0.970169, + "gen_feat_1": 490.3, + "gen_feat_2": 0.497807, + "gen_feat_3": 495.16 + } + }, + { + "id": "t_geocoding_gen_2", + "task_id": "t_geocoding", + "provider_id": "p_gen_2", + "name": "Google Maps Geocoding API (Gen p_gen_2)", + "features": { + "latency_ms": 293.3, + "cost_usd": 0.0, + "availability": 0.974652, + "gen_feat_1": 508.37, + "gen_feat_2": 0.500348, + "gen_feat_3": 495.48 + } + }, + { + "id": "t_geocoding_gen_3", + "task_id": "t_geocoding", + "provider_id": "p_gen_3", + "name": "Google Maps Geocoding API (Gen p_gen_3)", + "features": { + "latency_ms": 298.14, + "cost_usd": 0.0, + "availability": 0.985441, + "gen_feat_1": 501.06, + "gen_feat_2": 0.508714, + "gen_feat_3": 511.67 + } + }, + { + "id": "t_geocoding_gen_4", + "task_id": "t_geocoding", + "provider_id": "p_gen_4", + "name": "Google Maps Geocoding API (Gen p_gen_4)", + "features": { + "latency_ms": 296.31, + "cost_usd": 0.0, + "availability": 0.970937, + "gen_feat_1": 504.66, + "gen_feat_2": 0.485959, + "gen_feat_3": 506.47 + } + }, + { + "id": "t_geocoding_gen_5", + "task_id": "t_geocoding", + "provider_id": "p_gen_5", + "name": "Google Maps Geocoding API (Gen p_gen_5)", + "features": { + "latency_ms": 292.44, + "cost_usd": 0.0, + "availability": 0.970116, + "gen_feat_1": 506.54, + "gen_feat_2": 0.485388, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_geocoding_gen_6", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API (Gen p_google)", + "features": { + "latency_ms": 296.68, + "cost_usd": 0.0, + "availability": 0.979126, + "gen_feat_1": 503.49, + "gen_feat_2": 0.509299, + "gen_feat_3": 501.7 + } + }, + { + "id": "t_geocoding_gen_7", + "task_id": "t_geocoding", + "provider_id": "p_amazon", + "name": "Google Maps Geocoding API (Gen p_amazon)", + "features": { + "latency_ms": 299.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.43, + "gen_feat_2": 0.485447, + "gen_feat_3": 504.86 + } + }, + { + "id": "t_geocoding_gen_8", + "task_id": "t_geocoding", + "provider_id": "p_unimib", + "name": "Google Maps Geocoding API (Gen p_unimib)", + "features": { + "latency_ms": 291.86, + "cost_usd": 0.0, + "availability": 0.967929, + "gen_feat_1": 500.94, + "gen_feat_2": 0.487602, + "gen_feat_3": 501.12 + } + }, + { + "id": "t_geocoding_gen_9", + "task_id": "t_geocoding", + "provider_id": "p_archive", + "name": "Google Maps Geocoding API (Gen p_archive)", + "features": { + "latency_ms": 303.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.48, + "gen_feat_2": 0.494252, + "gen_feat_3": 501.53 + } + }, + { + "id": "t_transit_gen_2", + "task_id": "t_transit", + "provider_id": "p_local", + "name": "Google Transit API (Gen p_local)", + "features": { + "latency_ms": 447.81, + "cost_usd": 0.0, + "availability": 0.97876, + "gen_feat_1": 487.34, + "gen_feat_2": 0.494893, + "gen_feat_3": 492.66 + } + }, + { + "id": "t_transit_gen_3", + "task_id": "t_transit", + "provider_id": "p_gen_1", + "name": "Google Transit API (Gen p_gen_1)", + "features": { + "latency_ms": 454.73, + "cost_usd": 0.0, + "availability": 0.982378, + "gen_feat_1": 508.31, + "gen_feat_2": 0.486183, + "gen_feat_3": 501.39 + } + }, + { + "id": "t_transit_gen_4", + "task_id": "t_transit", + "provider_id": "p_gen_2", + "name": "Google Transit API (Gen p_gen_2)", + "features": { + "latency_ms": 463.1, + "cost_usd": 0.0, + "availability": 0.967212, + "gen_feat_1": 512.89, + "gen_feat_2": 0.512956, + "gen_feat_3": 495.23 + } + }, + { + "id": "t_transit_gen_5", + "task_id": "t_transit", + "provider_id": "p_gen_3", + "name": "Google Transit API (Gen p_gen_3)", + "features": { + "latency_ms": 456.23, + "cost_usd": 0.0, + "availability": 0.965992, + "gen_feat_1": 490.49, + "gen_feat_2": 0.508133, + "gen_feat_3": 504.92 + } + }, + { + "id": "t_transit_gen_6", + "task_id": "t_transit", + "provider_id": "p_gen_4", + "name": "Google Transit API (Gen p_gen_4)", + "features": { + "latency_ms": 440.18, + "cost_usd": 0.0, + "availability": 0.991733, + "gen_feat_1": 490.83, + "gen_feat_2": 0.504993, + "gen_feat_3": 492.89 + } + }, + { + "id": "t_transit_gen_7", + "task_id": "t_transit", + "provider_id": "p_gen_5", + "name": "Google Transit API (Gen p_gen_5)", + "features": { + "latency_ms": 462.92, + "cost_usd": 0.0, + "availability": 0.996902, + "gen_feat_1": 511.69, + "gen_feat_2": 0.506072, + "gen_feat_3": 487.84 + } + }, + { + "id": "t_transit_gen_8", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API (Gen p_google)", + "features": { + "latency_ms": 437.2, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 486.88, + "gen_feat_2": 0.486007, + "gen_feat_3": 512.05 + } + }, + { + "id": "t_transit_gen_9", + "task_id": "t_transit", + "provider_id": "p_amazon", + "name": "Google Transit API (Gen p_amazon)", + "features": { + "latency_ms": 454.11, + "cost_usd": 0.0, + "availability": 0.993251, + "gen_feat_1": 496.88, + "gen_feat_2": 0.494363, + "gen_feat_3": 508.7 + } + }, + { + "id": "t_archive_gen_2", + "task_id": "t_archive", + "provider_id": "p_unimib", + "name": "Archive.org API (Gen p_unimib)", + "features": { + "latency_ms": 491.38, + "cost_usd": 0.0, + "availability": 0.97419, + "gen_feat_1": 488.94, + "gen_feat_2": 0.490436, + "gen_feat_3": 502.27 + } + }, + { + "id": "t_archive_gen_3", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API (Gen p_archive)", + "features": { + "latency_ms": 493.0, + "cost_usd": 0.0, + "availability": 0.974135, + "gen_feat_1": 509.85, + "gen_feat_2": 0.501448, + "gen_feat_3": 508.14 + } + }, + { + "id": "t_archive_gen_4", + "task_id": "t_archive", + "provider_id": "p_local", + "name": "Archive.org API (Gen p_local)", + "features": { + "latency_ms": 506.7, + "cost_usd": 0.0, + "availability": 0.950007, + "gen_feat_1": 485.3, + "gen_feat_2": 0.506074, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_archive_gen_5", + "task_id": "t_archive", + "provider_id": "p_gen_1", + "name": "Archive.org API (Gen p_gen_1)", + "features": { + "latency_ms": 489.16, + "cost_usd": 0.0, + "availability": 0.997048, + "gen_feat_1": 498.8, + "gen_feat_2": 0.513697, + "gen_feat_3": 499.99 + } + }, + { + "id": "t_archive_gen_6", + "task_id": "t_archive", + "provider_id": "p_gen_2", + "name": "Archive.org API (Gen p_gen_2)", + "features": { + "latency_ms": 490.4, + "cost_usd": 0.0, + "availability": 0.989264, + "gen_feat_1": 499.32, + "gen_feat_2": 0.492021, + "gen_feat_3": 511.64 + } + }, + { + "id": "t_archive_gen_7", + "task_id": "t_archive", + "provider_id": "p_gen_3", + "name": "Archive.org API (Gen p_gen_3)", + "features": { + "latency_ms": 493.82, + "cost_usd": 0.0, + "availability": 0.963902, + "gen_feat_1": 513.54, + "gen_feat_2": 0.514704, + "gen_feat_3": 488.6 + } + }, + { + "id": "t_archive_gen_8", + "task_id": "t_archive", + "provider_id": "p_gen_4", + "name": "Archive.org API (Gen p_gen_4)", + "features": { + "latency_ms": 501.92, + "cost_usd": 0.0, + "availability": 0.987176, + "gen_feat_1": 487.31, + "gen_feat_2": 0.5052, + "gen_feat_3": 512.55 + } + }, + { + "id": "t_archive_gen_9", + "task_id": "t_archive", + "provider_id": "p_gen_5", + "name": "Archive.org API (Gen p_gen_5)", + "features": { + "latency_ms": 497.11, + "cost_usd": 0.0, + "availability": 0.959066, + "gen_feat_1": 489.18, + "gen_feat_2": 0.487091, + "gen_feat_3": 488.33 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_books", + "kind": "TASK", + "task_id": "t_books" + }, + { + "id": "n_parallel_options", + "kind": "AND", + "children": [ + { + "id": "n_amazon", + "kind": "TASK", + "task_id": "t_market" + }, + { + "id": "n_library_trip", + "kind": "SEQ", + "children": [ + { + "id": "n_opac", + "kind": "TASK", + "task_id": "t_library" + }, + { + "id": "n_geocode", + "kind": "TASK", + "task_id": "t_geocoding" + }, + { + "id": "n_transit", + "kind": "TASK", + "task_id": "t_transit" + } + ] + }, + { + "id": "n_archive", + "kind": "TASK", + "task_id": "t_archive" + } + ] + }, + { + "id": "n_report", + "kind": "ELEMENT", + "description": "Assemble final textbook access report" + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "availability" + ], + "weights": { + "availability": 1.0 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1357.94, + "hard": false + }, + { + "id": "gen_c_local_t_archive_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_archive" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_books", + "t_geocoding" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_archive", + "t_books" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/cremaschi2018-textbook-access_mono_utility_hard.json b/experimentation/instances/cremaschi2018-textbook-access_mono_utility_hard.json new file mode 100644 index 0000000..6aba0d6 --- /dev/null +++ b/experimentation/instances/cremaschi2018-textbook-access_mono_utility_hard.json @@ -0,0 +1,1202 @@ +{ + "metadata": { + "id": "cremaschi2018-textbook-access_mono_utility_hard", + "name": "Book info retrieval (Cremaschi et al. 2018) [mono_utility, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "QoS-aware instance derived from the running example in 'A Practical Approach to Services Composition Through Light Semantic Descriptions' (ESOCC 2018). QoS values are illustrative placeholders.", + "paper": { + "title": "A Practical Approach to Services Composition Through Light Semantic Descriptions", + "authors": "M. Cremaschi et al.", + "year": 2018, + "doi": "10.1007/978-3-319-99819-0_10" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Monetary cost per execution", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10 + } + }, + { + "id": "availability", + "name": "Service availability", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_google", + "name": "Google" + }, + { + "id": "p_amazon", + "name": "Amazon" + }, + { + "id": "p_unimib", + "name": "University of Milan - Bicocca (OPAC library)" + }, + { + "id": "p_archive", + "name": "Archive.org" + }, + { + "id": "p_local", + "name": "Local Application" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_books", + "name": "Retrieve book metadata from title (ISBN/author/title)" + }, + { + "id": "t_market", + "name": "Check e-commerce availability/price by ISBN" + }, + { + "id": "t_library", + "name": "Check library availability and retrieve library address" + }, + { + "id": "t_geocoding", + "name": "Geocode library address into coordinates" + }, + { + "id": "t_transit", + "name": "Retrieve public transport options to the library" + }, + { + "id": "t_archive", + "name": "Check free eBook availability (Archive.org)" + } + ], + "candidates": [ + { + "id": "c_google_books_api", + "task_id": "t_books", + "provider_id": "p_google", + "name": "Google Books API", + "features": { + "latency_ms": 250, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_amazon_market_api", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API", + "features": { + "latency_ms": 400, + "cost_usd": 0.001, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_opac_library_api", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API", + "features": { + "latency_ms": 350, + "cost_usd": 0.0001, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_geocoding_api", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API", + "features": { + "latency_ms": 300, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_transit_api", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API", + "features": { + "latency_ms": 450, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_archive_api", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API", + "features": { + "latency_ms": 500, + "cost_usd": 0.0001, + "availability": 0.97, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_books_gen_1", + "task_id": "t_books", + "provider_id": "p_gen_shared", + "name": "Google Books API (Gen Shared)", + "features": { + "latency_ms": 250.27, + "cost_usd": 0.0, + "availability": 0.970656, + "gen_feat_1": 507.35, + "gen_feat_2": 0.498346, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_market_gen_1", + "task_id": "t_market", + "provider_id": "p_gen_shared", + "name": "Amazon Market API (Gen Shared)", + "features": { + "latency_ms": 410.3, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.37, + "gen_feat_2": 0.4873, + "gen_feat_3": 499.78 + } + }, + { + "id": "t_library_gen_1", + "task_id": "t_library", + "provider_id": "p_gen_shared", + "name": "OPAC Library API (Gen Shared)", + "features": { + "latency_ms": 350.22, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 503.36, + "gen_feat_2": 0.490142, + "gen_feat_3": 513.01 + } + }, + { + "id": "t_geocoding_gen_1", + "task_id": "t_geocoding", + "provider_id": "p_gen_shared", + "name": "Google Maps Geocoding API (Gen Shared)", + "features": { + "latency_ms": 299.52, + "cost_usd": 0.0, + "availability": 0.970921, + "gen_feat_1": 509.42, + "gen_feat_2": 0.491433, + "gen_feat_3": 503.84 + } + }, + { + "id": "t_transit_gen_1", + "task_id": "t_transit", + "provider_id": "p_gen_shared", + "name": "Google Transit API (Gen Shared)", + "features": { + "latency_ms": 457.93, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.8, + "gen_feat_2": 0.5146, + "gen_feat_3": 509.74 + } + }, + { + "id": "t_archive_gen_1", + "task_id": "t_archive", + "provider_id": "p_gen_shared", + "name": "Archive.org API (Gen Shared)", + "features": { + "latency_ms": 494.4, + "cost_usd": 0.0, + "availability": 0.973217, + "gen_feat_1": 486.21, + "gen_feat_2": 0.487758, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_books_gen_2", + "task_id": "t_books", + "provider_id": "p_unimib", + "name": "Google Books API (Gen p_unimib)", + "features": { + "latency_ms": 251.51, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.43, + "gen_feat_2": 0.49659, + "gen_feat_3": 492.56 + } + }, + { + "id": "t_books_gen_3", + "task_id": "t_books", + "provider_id": "p_archive", + "name": "Google Books API (Gen p_archive)", + "features": { + "latency_ms": 253.59, + "cost_usd": 0.0, + "availability": 0.976832, + "gen_feat_1": 498.31, + "gen_feat_2": 0.504989, + "gen_feat_3": 485.73 + } + }, + { + "id": "t_books_gen_4", + "task_id": "t_books", + "provider_id": "p_local", + "name": "Google Books API (Gen p_local)", + "features": { + "latency_ms": 253.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 496.81, + "gen_feat_2": 0.509742, + "gen_feat_3": 503.82 + } + }, + { + "id": "t_books_gen_5", + "task_id": "t_books", + "provider_id": "p_gen_1", + "name": "Google Books API (Gen p_gen_1)", + "features": { + "latency_ms": 243.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.29, + "gen_feat_2": 0.497801, + "gen_feat_3": 491.8 + } + }, + { + "id": "t_books_gen_6", + "task_id": "t_books", + "provider_id": "p_gen_2", + "name": "Google Books API (Gen p_gen_2)", + "features": { + "latency_ms": 249.33, + "cost_usd": 0.0, + "availability": 0.968324, + "gen_feat_1": 500.1, + "gen_feat_2": 0.489322, + "gen_feat_3": 486.96 + } + }, + { + "id": "t_books_gen_7", + "task_id": "t_books", + "provider_id": "p_gen_3", + "name": "Google Books API (Gen p_gen_3)", + "features": { + "latency_ms": 244.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.49, + "gen_feat_2": 0.509901, + "gen_feat_3": 510.32 + } + }, + { + "id": "t_books_gen_8", + "task_id": "t_books", + "provider_id": "p_gen_4", + "name": "Google Books API (Gen p_gen_4)", + "features": { + "latency_ms": 249.93, + "cost_usd": 0.0, + "availability": 0.984683, + "gen_feat_1": 503.61, + "gen_feat_2": 0.501017, + "gen_feat_3": 501.49 + } + }, + { + "id": "t_books_gen_9", + "task_id": "t_books", + "provider_id": "p_gen_5", + "name": "Google Books API (Gen p_gen_5)", + "features": { + "latency_ms": 252.75, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 505.53, + "gen_feat_2": 0.491572, + "gen_feat_3": 506.63 + } + }, + { + "id": "t_market_gen_2", + "task_id": "t_market", + "provider_id": "p_google", + "name": "Amazon Market API (Gen p_google)", + "features": { + "latency_ms": 390.51, + "cost_usd": 0.0, + "availability": 0.974193, + "gen_feat_1": 514.03, + "gen_feat_2": 0.504606, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_market_gen_3", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API (Gen p_amazon)", + "features": { + "latency_ms": 390.29, + "cost_usd": 0.0, + "availability": 0.964065, + "gen_feat_1": 490.39, + "gen_feat_2": 0.510618, + "gen_feat_3": 500.06 + } + }, + { + "id": "t_market_gen_4", + "task_id": "t_market", + "provider_id": "p_unimib", + "name": "Amazon Market API (Gen p_unimib)", + "features": { + "latency_ms": 403.22, + "cost_usd": 0.0, + "availability": 0.98629, + "gen_feat_1": 506.11, + "gen_feat_2": 0.504836, + "gen_feat_3": 513.95 + } + }, + { + "id": "t_market_gen_5", + "task_id": "t_market", + "provider_id": "p_archive", + "name": "Amazon Market API (Gen p_archive)", + "features": { + "latency_ms": 392.94, + "cost_usd": 0.0, + "availability": 0.963527, + "gen_feat_1": 512.48, + "gen_feat_2": 0.514296, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_market_gen_6", + "task_id": "t_market", + "provider_id": "p_local", + "name": "Amazon Market API (Gen p_local)", + "features": { + "latency_ms": 393.03, + "cost_usd": 0.0, + "availability": 0.981369, + "gen_feat_1": 488.34, + "gen_feat_2": 0.514668, + "gen_feat_3": 505.0 + } + }, + { + "id": "t_market_gen_7", + "task_id": "t_market", + "provider_id": "p_gen_1", + "name": "Amazon Market API (Gen p_gen_1)", + "features": { + "latency_ms": 411.7, + "cost_usd": 0.0, + "availability": 0.985823, + "gen_feat_1": 500.86, + "gen_feat_2": 0.497755, + "gen_feat_3": 497.03 + } + }, + { + "id": "t_market_gen_8", + "task_id": "t_market", + "provider_id": "p_gen_2", + "name": "Amazon Market API (Gen p_gen_2)", + "features": { + "latency_ms": 402.71, + "cost_usd": 0.0, + "availability": 0.991509, + "gen_feat_1": 505.13, + "gen_feat_2": 0.49775, + "gen_feat_3": 491.63 + } + }, + { + "id": "t_market_gen_9", + "task_id": "t_market", + "provider_id": "p_gen_3", + "name": "Amazon Market API (Gen p_gen_3)", + "features": { + "latency_ms": 402.55, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 510.3, + "gen_feat_2": 0.501032, + "gen_feat_3": 505.68 + } + }, + { + "id": "t_library_gen_2", + "task_id": "t_library", + "provider_id": "p_gen_4", + "name": "OPAC Library API (Gen p_gen_4)", + "features": { + "latency_ms": 345.85, + "cost_usd": 0.0, + "availability": 0.97661, + "gen_feat_1": 508.48, + "gen_feat_2": 0.509068, + "gen_feat_3": 505.91 + } + }, + { + "id": "t_library_gen_3", + "task_id": "t_library", + "provider_id": "p_gen_5", + "name": "OPAC Library API (Gen p_gen_5)", + "features": { + "latency_ms": 357.65, + "cost_usd": 0.0, + "availability": 0.995668, + "gen_feat_1": 511.52, + "gen_feat_2": 0.489245, + "gen_feat_3": 489.95 + } + }, + { + "id": "t_library_gen_4", + "task_id": "t_library", + "provider_id": "p_google", + "name": "OPAC Library API (Gen p_google)", + "features": { + "latency_ms": 347.46, + "cost_usd": 0.0, + "availability": 0.961356, + "gen_feat_1": 510.48, + "gen_feat_2": 0.509522, + "gen_feat_3": 510.51 + } + }, + { + "id": "t_library_gen_5", + "task_id": "t_library", + "provider_id": "p_amazon", + "name": "OPAC Library API (Gen p_amazon)", + "features": { + "latency_ms": 346.07, + "cost_usd": 0.0, + "availability": 0.99049, + "gen_feat_1": 510.53, + "gen_feat_2": 0.488512, + "gen_feat_3": 513.85 + } + }, + { + "id": "t_library_gen_6", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API (Gen p_unimib)", + "features": { + "latency_ms": 353.12, + "cost_usd": 0.0, + "availability": 0.966548, + "gen_feat_1": 500.27, + "gen_feat_2": 0.497436, + "gen_feat_3": 511.73 + } + }, + { + "id": "t_library_gen_7", + "task_id": "t_library", + "provider_id": "p_archive", + "name": "OPAC Library API (Gen p_archive)", + "features": { + "latency_ms": 356.85, + "cost_usd": 0.0, + "availability": 0.993546, + "gen_feat_1": 510.3, + "gen_feat_2": 0.513619, + "gen_feat_3": 511.4 + } + }, + { + "id": "t_library_gen_8", + "task_id": "t_library", + "provider_id": "p_local", + "name": "OPAC Library API (Gen p_local)", + "features": { + "latency_ms": 357.15, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.06, + "gen_feat_2": 0.487388, + "gen_feat_3": 498.18 + } + }, + { + "id": "t_library_gen_9", + "task_id": "t_library", + "provider_id": "p_gen_1", + "name": "OPAC Library API (Gen p_gen_1)", + "features": { + "latency_ms": 355.46, + "cost_usd": 0.0, + "availability": 0.970169, + "gen_feat_1": 490.3, + "gen_feat_2": 0.497807, + "gen_feat_3": 495.16 + } + }, + { + "id": "t_geocoding_gen_2", + "task_id": "t_geocoding", + "provider_id": "p_gen_2", + "name": "Google Maps Geocoding API (Gen p_gen_2)", + "features": { + "latency_ms": 293.3, + "cost_usd": 0.0, + "availability": 0.974652, + "gen_feat_1": 508.37, + "gen_feat_2": 0.500348, + "gen_feat_3": 495.48 + } + }, + { + "id": "t_geocoding_gen_3", + "task_id": "t_geocoding", + "provider_id": "p_gen_3", + "name": "Google Maps Geocoding API (Gen p_gen_3)", + "features": { + "latency_ms": 298.14, + "cost_usd": 0.0, + "availability": 0.985441, + "gen_feat_1": 501.06, + "gen_feat_2": 0.508714, + "gen_feat_3": 511.67 + } + }, + { + "id": "t_geocoding_gen_4", + "task_id": "t_geocoding", + "provider_id": "p_gen_4", + "name": "Google Maps Geocoding API (Gen p_gen_4)", + "features": { + "latency_ms": 296.31, + "cost_usd": 0.0, + "availability": 0.970937, + "gen_feat_1": 504.66, + "gen_feat_2": 0.485959, + "gen_feat_3": 506.47 + } + }, + { + "id": "t_geocoding_gen_5", + "task_id": "t_geocoding", + "provider_id": "p_gen_5", + "name": "Google Maps Geocoding API (Gen p_gen_5)", + "features": { + "latency_ms": 292.44, + "cost_usd": 0.0, + "availability": 0.970116, + "gen_feat_1": 506.54, + "gen_feat_2": 0.485388, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_geocoding_gen_6", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API (Gen p_google)", + "features": { + "latency_ms": 296.68, + "cost_usd": 0.0, + "availability": 0.979126, + "gen_feat_1": 503.49, + "gen_feat_2": 0.509299, + "gen_feat_3": 501.7 + } + }, + { + "id": "t_geocoding_gen_7", + "task_id": "t_geocoding", + "provider_id": "p_amazon", + "name": "Google Maps Geocoding API (Gen p_amazon)", + "features": { + "latency_ms": 299.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.43, + "gen_feat_2": 0.485447, + "gen_feat_3": 504.86 + } + }, + { + "id": "t_geocoding_gen_8", + "task_id": "t_geocoding", + "provider_id": "p_unimib", + "name": "Google Maps Geocoding API (Gen p_unimib)", + "features": { + "latency_ms": 291.86, + "cost_usd": 0.0, + "availability": 0.967929, + "gen_feat_1": 500.94, + "gen_feat_2": 0.487602, + "gen_feat_3": 501.12 + } + }, + { + "id": "t_geocoding_gen_9", + "task_id": "t_geocoding", + "provider_id": "p_archive", + "name": "Google Maps Geocoding API (Gen p_archive)", + "features": { + "latency_ms": 303.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.48, + "gen_feat_2": 0.494252, + "gen_feat_3": 501.53 + } + }, + { + "id": "t_transit_gen_2", + "task_id": "t_transit", + "provider_id": "p_local", + "name": "Google Transit API (Gen p_local)", + "features": { + "latency_ms": 447.81, + "cost_usd": 0.0, + "availability": 0.97876, + "gen_feat_1": 487.34, + "gen_feat_2": 0.494893, + "gen_feat_3": 492.66 + } + }, + { + "id": "t_transit_gen_3", + "task_id": "t_transit", + "provider_id": "p_gen_1", + "name": "Google Transit API (Gen p_gen_1)", + "features": { + "latency_ms": 454.73, + "cost_usd": 0.0, + "availability": 0.982378, + "gen_feat_1": 508.31, + "gen_feat_2": 0.486183, + "gen_feat_3": 501.39 + } + }, + { + "id": "t_transit_gen_4", + "task_id": "t_transit", + "provider_id": "p_gen_2", + "name": "Google Transit API (Gen p_gen_2)", + "features": { + "latency_ms": 463.1, + "cost_usd": 0.0, + "availability": 0.967212, + "gen_feat_1": 512.89, + "gen_feat_2": 0.512956, + "gen_feat_3": 495.23 + } + }, + { + "id": "t_transit_gen_5", + "task_id": "t_transit", + "provider_id": "p_gen_3", + "name": "Google Transit API (Gen p_gen_3)", + "features": { + "latency_ms": 456.23, + "cost_usd": 0.0, + "availability": 0.965992, + "gen_feat_1": 490.49, + "gen_feat_2": 0.508133, + "gen_feat_3": 504.92 + } + }, + { + "id": "t_transit_gen_6", + "task_id": "t_transit", + "provider_id": "p_gen_4", + "name": "Google Transit API (Gen p_gen_4)", + "features": { + "latency_ms": 440.18, + "cost_usd": 0.0, + "availability": 0.991733, + "gen_feat_1": 490.83, + "gen_feat_2": 0.504993, + "gen_feat_3": 492.89 + } + }, + { + "id": "t_transit_gen_7", + "task_id": "t_transit", + "provider_id": "p_gen_5", + "name": "Google Transit API (Gen p_gen_5)", + "features": { + "latency_ms": 462.92, + "cost_usd": 0.0, + "availability": 0.996902, + "gen_feat_1": 511.69, + "gen_feat_2": 0.506072, + "gen_feat_3": 487.84 + } + }, + { + "id": "t_transit_gen_8", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API (Gen p_google)", + "features": { + "latency_ms": 437.2, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 486.88, + "gen_feat_2": 0.486007, + "gen_feat_3": 512.05 + } + }, + { + "id": "t_transit_gen_9", + "task_id": "t_transit", + "provider_id": "p_amazon", + "name": "Google Transit API (Gen p_amazon)", + "features": { + "latency_ms": 454.11, + "cost_usd": 0.0, + "availability": 0.993251, + "gen_feat_1": 496.88, + "gen_feat_2": 0.494363, + "gen_feat_3": 508.7 + } + }, + { + "id": "t_archive_gen_2", + "task_id": "t_archive", + "provider_id": "p_unimib", + "name": "Archive.org API (Gen p_unimib)", + "features": { + "latency_ms": 491.38, + "cost_usd": 0.0, + "availability": 0.97419, + "gen_feat_1": 488.94, + "gen_feat_2": 0.490436, + "gen_feat_3": 502.27 + } + }, + { + "id": "t_archive_gen_3", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API (Gen p_archive)", + "features": { + "latency_ms": 493.0, + "cost_usd": 0.0, + "availability": 0.974135, + "gen_feat_1": 509.85, + "gen_feat_2": 0.501448, + "gen_feat_3": 508.14 + } + }, + { + "id": "t_archive_gen_4", + "task_id": "t_archive", + "provider_id": "p_local", + "name": "Archive.org API (Gen p_local)", + "features": { + "latency_ms": 506.7, + "cost_usd": 0.0, + "availability": 0.950007, + "gen_feat_1": 485.3, + "gen_feat_2": 0.506074, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_archive_gen_5", + "task_id": "t_archive", + "provider_id": "p_gen_1", + "name": "Archive.org API (Gen p_gen_1)", + "features": { + "latency_ms": 489.16, + "cost_usd": 0.0, + "availability": 0.997048, + "gen_feat_1": 498.8, + "gen_feat_2": 0.513697, + "gen_feat_3": 499.99 + } + }, + { + "id": "t_archive_gen_6", + "task_id": "t_archive", + "provider_id": "p_gen_2", + "name": "Archive.org API (Gen p_gen_2)", + "features": { + "latency_ms": 490.4, + "cost_usd": 0.0, + "availability": 0.989264, + "gen_feat_1": 499.32, + "gen_feat_2": 0.492021, + "gen_feat_3": 511.64 + } + }, + { + "id": "t_archive_gen_7", + "task_id": "t_archive", + "provider_id": "p_gen_3", + "name": "Archive.org API (Gen p_gen_3)", + "features": { + "latency_ms": 493.82, + "cost_usd": 0.0, + "availability": 0.963902, + "gen_feat_1": 513.54, + "gen_feat_2": 0.514704, + "gen_feat_3": 488.6 + } + }, + { + "id": "t_archive_gen_8", + "task_id": "t_archive", + "provider_id": "p_gen_4", + "name": "Archive.org API (Gen p_gen_4)", + "features": { + "latency_ms": 501.92, + "cost_usd": 0.0, + "availability": 0.987176, + "gen_feat_1": 487.31, + "gen_feat_2": 0.5052, + "gen_feat_3": 512.55 + } + }, + { + "id": "t_archive_gen_9", + "task_id": "t_archive", + "provider_id": "p_gen_5", + "name": "Archive.org API (Gen p_gen_5)", + "features": { + "latency_ms": 497.11, + "cost_usd": 0.0, + "availability": 0.959066, + "gen_feat_1": 489.18, + "gen_feat_2": 0.487091, + "gen_feat_3": 488.33 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_books", + "kind": "TASK", + "task_id": "t_books" + }, + { + "id": "n_parallel_options", + "kind": "AND", + "children": [ + { + "id": "n_amazon", + "kind": "TASK", + "task_id": "t_market" + }, + { + "id": "n_library_trip", + "kind": "SEQ", + "children": [ + { + "id": "n_opac", + "kind": "TASK", + "task_id": "t_library" + }, + { + "id": "n_geocode", + "kind": "TASK", + "task_id": "t_geocoding" + }, + { + "id": "n_transit", + "kind": "TASK", + "task_id": "t_transit" + } + ] + }, + { + "id": "n_archive", + "kind": "TASK", + "task_id": "t_archive" + } + ] + }, + { + "id": "n_report", + "kind": "ELEMENT", + "description": "Assemble final textbook access report" + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1357.94, + "hard": true + }, + { + "id": "gen_c_local_t_archive_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_archive" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_books", + "t_geocoding" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_archive", + "t_books" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/cremaschi2018-textbook-access_mono_utility_soft.json b/experimentation/instances/cremaschi2018-textbook-access_mono_utility_soft.json new file mode 100644 index 0000000..b8214e7 --- /dev/null +++ b/experimentation/instances/cremaschi2018-textbook-access_mono_utility_soft.json @@ -0,0 +1,1202 @@ +{ + "metadata": { + "id": "cremaschi2018-textbook-access_mono_utility_soft", + "name": "Book info retrieval (Cremaschi et al. 2018) [mono_utility, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "QoS-aware instance derived from the running example in 'A Practical Approach to Services Composition Through Light Semantic Descriptions' (ESOCC 2018). QoS values are illustrative placeholders.", + "paper": { + "title": "A Practical Approach to Services Composition Through Light Semantic Descriptions", + "authors": "M. Cremaschi et al.", + "year": 2018, + "doi": "10.1007/978-3-319-99819-0_10" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Monetary cost per execution", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10 + } + }, + { + "id": "availability", + "name": "Service availability", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_google", + "name": "Google" + }, + { + "id": "p_amazon", + "name": "Amazon" + }, + { + "id": "p_unimib", + "name": "University of Milan - Bicocca (OPAC library)" + }, + { + "id": "p_archive", + "name": "Archive.org" + }, + { + "id": "p_local", + "name": "Local Application" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_books", + "name": "Retrieve book metadata from title (ISBN/author/title)" + }, + { + "id": "t_market", + "name": "Check e-commerce availability/price by ISBN" + }, + { + "id": "t_library", + "name": "Check library availability and retrieve library address" + }, + { + "id": "t_geocoding", + "name": "Geocode library address into coordinates" + }, + { + "id": "t_transit", + "name": "Retrieve public transport options to the library" + }, + { + "id": "t_archive", + "name": "Check free eBook availability (Archive.org)" + } + ], + "candidates": [ + { + "id": "c_google_books_api", + "task_id": "t_books", + "provider_id": "p_google", + "name": "Google Books API", + "features": { + "latency_ms": 250, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_amazon_market_api", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API", + "features": { + "latency_ms": 400, + "cost_usd": 0.001, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_opac_library_api", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API", + "features": { + "latency_ms": 350, + "cost_usd": 0.0001, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_geocoding_api", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API", + "features": { + "latency_ms": 300, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_transit_api", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API", + "features": { + "latency_ms": 450, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_archive_api", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API", + "features": { + "latency_ms": 500, + "cost_usd": 0.0001, + "availability": 0.97, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_books_gen_1", + "task_id": "t_books", + "provider_id": "p_gen_shared", + "name": "Google Books API (Gen Shared)", + "features": { + "latency_ms": 250.27, + "cost_usd": 0.0, + "availability": 0.970656, + "gen_feat_1": 507.35, + "gen_feat_2": 0.498346, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_market_gen_1", + "task_id": "t_market", + "provider_id": "p_gen_shared", + "name": "Amazon Market API (Gen Shared)", + "features": { + "latency_ms": 410.3, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.37, + "gen_feat_2": 0.4873, + "gen_feat_3": 499.78 + } + }, + { + "id": "t_library_gen_1", + "task_id": "t_library", + "provider_id": "p_gen_shared", + "name": "OPAC Library API (Gen Shared)", + "features": { + "latency_ms": 350.22, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 503.36, + "gen_feat_2": 0.490142, + "gen_feat_3": 513.01 + } + }, + { + "id": "t_geocoding_gen_1", + "task_id": "t_geocoding", + "provider_id": "p_gen_shared", + "name": "Google Maps Geocoding API (Gen Shared)", + "features": { + "latency_ms": 299.52, + "cost_usd": 0.0, + "availability": 0.970921, + "gen_feat_1": 509.42, + "gen_feat_2": 0.491433, + "gen_feat_3": 503.84 + } + }, + { + "id": "t_transit_gen_1", + "task_id": "t_transit", + "provider_id": "p_gen_shared", + "name": "Google Transit API (Gen Shared)", + "features": { + "latency_ms": 457.93, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.8, + "gen_feat_2": 0.5146, + "gen_feat_3": 509.74 + } + }, + { + "id": "t_archive_gen_1", + "task_id": "t_archive", + "provider_id": "p_gen_shared", + "name": "Archive.org API (Gen Shared)", + "features": { + "latency_ms": 494.4, + "cost_usd": 0.0, + "availability": 0.973217, + "gen_feat_1": 486.21, + "gen_feat_2": 0.487758, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_books_gen_2", + "task_id": "t_books", + "provider_id": "p_unimib", + "name": "Google Books API (Gen p_unimib)", + "features": { + "latency_ms": 251.51, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.43, + "gen_feat_2": 0.49659, + "gen_feat_3": 492.56 + } + }, + { + "id": "t_books_gen_3", + "task_id": "t_books", + "provider_id": "p_archive", + "name": "Google Books API (Gen p_archive)", + "features": { + "latency_ms": 253.59, + "cost_usd": 0.0, + "availability": 0.976832, + "gen_feat_1": 498.31, + "gen_feat_2": 0.504989, + "gen_feat_3": 485.73 + } + }, + { + "id": "t_books_gen_4", + "task_id": "t_books", + "provider_id": "p_local", + "name": "Google Books API (Gen p_local)", + "features": { + "latency_ms": 253.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 496.81, + "gen_feat_2": 0.509742, + "gen_feat_3": 503.82 + } + }, + { + "id": "t_books_gen_5", + "task_id": "t_books", + "provider_id": "p_gen_1", + "name": "Google Books API (Gen p_gen_1)", + "features": { + "latency_ms": 243.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.29, + "gen_feat_2": 0.497801, + "gen_feat_3": 491.8 + } + }, + { + "id": "t_books_gen_6", + "task_id": "t_books", + "provider_id": "p_gen_2", + "name": "Google Books API (Gen p_gen_2)", + "features": { + "latency_ms": 249.33, + "cost_usd": 0.0, + "availability": 0.968324, + "gen_feat_1": 500.1, + "gen_feat_2": 0.489322, + "gen_feat_3": 486.96 + } + }, + { + "id": "t_books_gen_7", + "task_id": "t_books", + "provider_id": "p_gen_3", + "name": "Google Books API (Gen p_gen_3)", + "features": { + "latency_ms": 244.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.49, + "gen_feat_2": 0.509901, + "gen_feat_3": 510.32 + } + }, + { + "id": "t_books_gen_8", + "task_id": "t_books", + "provider_id": "p_gen_4", + "name": "Google Books API (Gen p_gen_4)", + "features": { + "latency_ms": 249.93, + "cost_usd": 0.0, + "availability": 0.984683, + "gen_feat_1": 503.61, + "gen_feat_2": 0.501017, + "gen_feat_3": 501.49 + } + }, + { + "id": "t_books_gen_9", + "task_id": "t_books", + "provider_id": "p_gen_5", + "name": "Google Books API (Gen p_gen_5)", + "features": { + "latency_ms": 252.75, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 505.53, + "gen_feat_2": 0.491572, + "gen_feat_3": 506.63 + } + }, + { + "id": "t_market_gen_2", + "task_id": "t_market", + "provider_id": "p_google", + "name": "Amazon Market API (Gen p_google)", + "features": { + "latency_ms": 390.51, + "cost_usd": 0.0, + "availability": 0.974193, + "gen_feat_1": 514.03, + "gen_feat_2": 0.504606, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_market_gen_3", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API (Gen p_amazon)", + "features": { + "latency_ms": 390.29, + "cost_usd": 0.0, + "availability": 0.964065, + "gen_feat_1": 490.39, + "gen_feat_2": 0.510618, + "gen_feat_3": 500.06 + } + }, + { + "id": "t_market_gen_4", + "task_id": "t_market", + "provider_id": "p_unimib", + "name": "Amazon Market API (Gen p_unimib)", + "features": { + "latency_ms": 403.22, + "cost_usd": 0.0, + "availability": 0.98629, + "gen_feat_1": 506.11, + "gen_feat_2": 0.504836, + "gen_feat_3": 513.95 + } + }, + { + "id": "t_market_gen_5", + "task_id": "t_market", + "provider_id": "p_archive", + "name": "Amazon Market API (Gen p_archive)", + "features": { + "latency_ms": 392.94, + "cost_usd": 0.0, + "availability": 0.963527, + "gen_feat_1": 512.48, + "gen_feat_2": 0.514296, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_market_gen_6", + "task_id": "t_market", + "provider_id": "p_local", + "name": "Amazon Market API (Gen p_local)", + "features": { + "latency_ms": 393.03, + "cost_usd": 0.0, + "availability": 0.981369, + "gen_feat_1": 488.34, + "gen_feat_2": 0.514668, + "gen_feat_3": 505.0 + } + }, + { + "id": "t_market_gen_7", + "task_id": "t_market", + "provider_id": "p_gen_1", + "name": "Amazon Market API (Gen p_gen_1)", + "features": { + "latency_ms": 411.7, + "cost_usd": 0.0, + "availability": 0.985823, + "gen_feat_1": 500.86, + "gen_feat_2": 0.497755, + "gen_feat_3": 497.03 + } + }, + { + "id": "t_market_gen_8", + "task_id": "t_market", + "provider_id": "p_gen_2", + "name": "Amazon Market API (Gen p_gen_2)", + "features": { + "latency_ms": 402.71, + "cost_usd": 0.0, + "availability": 0.991509, + "gen_feat_1": 505.13, + "gen_feat_2": 0.49775, + "gen_feat_3": 491.63 + } + }, + { + "id": "t_market_gen_9", + "task_id": "t_market", + "provider_id": "p_gen_3", + "name": "Amazon Market API (Gen p_gen_3)", + "features": { + "latency_ms": 402.55, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 510.3, + "gen_feat_2": 0.501032, + "gen_feat_3": 505.68 + } + }, + { + "id": "t_library_gen_2", + "task_id": "t_library", + "provider_id": "p_gen_4", + "name": "OPAC Library API (Gen p_gen_4)", + "features": { + "latency_ms": 345.85, + "cost_usd": 0.0, + "availability": 0.97661, + "gen_feat_1": 508.48, + "gen_feat_2": 0.509068, + "gen_feat_3": 505.91 + } + }, + { + "id": "t_library_gen_3", + "task_id": "t_library", + "provider_id": "p_gen_5", + "name": "OPAC Library API (Gen p_gen_5)", + "features": { + "latency_ms": 357.65, + "cost_usd": 0.0, + "availability": 0.995668, + "gen_feat_1": 511.52, + "gen_feat_2": 0.489245, + "gen_feat_3": 489.95 + } + }, + { + "id": "t_library_gen_4", + "task_id": "t_library", + "provider_id": "p_google", + "name": "OPAC Library API (Gen p_google)", + "features": { + "latency_ms": 347.46, + "cost_usd": 0.0, + "availability": 0.961356, + "gen_feat_1": 510.48, + "gen_feat_2": 0.509522, + "gen_feat_3": 510.51 + } + }, + { + "id": "t_library_gen_5", + "task_id": "t_library", + "provider_id": "p_amazon", + "name": "OPAC Library API (Gen p_amazon)", + "features": { + "latency_ms": 346.07, + "cost_usd": 0.0, + "availability": 0.99049, + "gen_feat_1": 510.53, + "gen_feat_2": 0.488512, + "gen_feat_3": 513.85 + } + }, + { + "id": "t_library_gen_6", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API (Gen p_unimib)", + "features": { + "latency_ms": 353.12, + "cost_usd": 0.0, + "availability": 0.966548, + "gen_feat_1": 500.27, + "gen_feat_2": 0.497436, + "gen_feat_3": 511.73 + } + }, + { + "id": "t_library_gen_7", + "task_id": "t_library", + "provider_id": "p_archive", + "name": "OPAC Library API (Gen p_archive)", + "features": { + "latency_ms": 356.85, + "cost_usd": 0.0, + "availability": 0.993546, + "gen_feat_1": 510.3, + "gen_feat_2": 0.513619, + "gen_feat_3": 511.4 + } + }, + { + "id": "t_library_gen_8", + "task_id": "t_library", + "provider_id": "p_local", + "name": "OPAC Library API (Gen p_local)", + "features": { + "latency_ms": 357.15, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.06, + "gen_feat_2": 0.487388, + "gen_feat_3": 498.18 + } + }, + { + "id": "t_library_gen_9", + "task_id": "t_library", + "provider_id": "p_gen_1", + "name": "OPAC Library API (Gen p_gen_1)", + "features": { + "latency_ms": 355.46, + "cost_usd": 0.0, + "availability": 0.970169, + "gen_feat_1": 490.3, + "gen_feat_2": 0.497807, + "gen_feat_3": 495.16 + } + }, + { + "id": "t_geocoding_gen_2", + "task_id": "t_geocoding", + "provider_id": "p_gen_2", + "name": "Google Maps Geocoding API (Gen p_gen_2)", + "features": { + "latency_ms": 293.3, + "cost_usd": 0.0, + "availability": 0.974652, + "gen_feat_1": 508.37, + "gen_feat_2": 0.500348, + "gen_feat_3": 495.48 + } + }, + { + "id": "t_geocoding_gen_3", + "task_id": "t_geocoding", + "provider_id": "p_gen_3", + "name": "Google Maps Geocoding API (Gen p_gen_3)", + "features": { + "latency_ms": 298.14, + "cost_usd": 0.0, + "availability": 0.985441, + "gen_feat_1": 501.06, + "gen_feat_2": 0.508714, + "gen_feat_3": 511.67 + } + }, + { + "id": "t_geocoding_gen_4", + "task_id": "t_geocoding", + "provider_id": "p_gen_4", + "name": "Google Maps Geocoding API (Gen p_gen_4)", + "features": { + "latency_ms": 296.31, + "cost_usd": 0.0, + "availability": 0.970937, + "gen_feat_1": 504.66, + "gen_feat_2": 0.485959, + "gen_feat_3": 506.47 + } + }, + { + "id": "t_geocoding_gen_5", + "task_id": "t_geocoding", + "provider_id": "p_gen_5", + "name": "Google Maps Geocoding API (Gen p_gen_5)", + "features": { + "latency_ms": 292.44, + "cost_usd": 0.0, + "availability": 0.970116, + "gen_feat_1": 506.54, + "gen_feat_2": 0.485388, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_geocoding_gen_6", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API (Gen p_google)", + "features": { + "latency_ms": 296.68, + "cost_usd": 0.0, + "availability": 0.979126, + "gen_feat_1": 503.49, + "gen_feat_2": 0.509299, + "gen_feat_3": 501.7 + } + }, + { + "id": "t_geocoding_gen_7", + "task_id": "t_geocoding", + "provider_id": "p_amazon", + "name": "Google Maps Geocoding API (Gen p_amazon)", + "features": { + "latency_ms": 299.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.43, + "gen_feat_2": 0.485447, + "gen_feat_3": 504.86 + } + }, + { + "id": "t_geocoding_gen_8", + "task_id": "t_geocoding", + "provider_id": "p_unimib", + "name": "Google Maps Geocoding API (Gen p_unimib)", + "features": { + "latency_ms": 291.86, + "cost_usd": 0.0, + "availability": 0.967929, + "gen_feat_1": 500.94, + "gen_feat_2": 0.487602, + "gen_feat_3": 501.12 + } + }, + { + "id": "t_geocoding_gen_9", + "task_id": "t_geocoding", + "provider_id": "p_archive", + "name": "Google Maps Geocoding API (Gen p_archive)", + "features": { + "latency_ms": 303.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.48, + "gen_feat_2": 0.494252, + "gen_feat_3": 501.53 + } + }, + { + "id": "t_transit_gen_2", + "task_id": "t_transit", + "provider_id": "p_local", + "name": "Google Transit API (Gen p_local)", + "features": { + "latency_ms": 447.81, + "cost_usd": 0.0, + "availability": 0.97876, + "gen_feat_1": 487.34, + "gen_feat_2": 0.494893, + "gen_feat_3": 492.66 + } + }, + { + "id": "t_transit_gen_3", + "task_id": "t_transit", + "provider_id": "p_gen_1", + "name": "Google Transit API (Gen p_gen_1)", + "features": { + "latency_ms": 454.73, + "cost_usd": 0.0, + "availability": 0.982378, + "gen_feat_1": 508.31, + "gen_feat_2": 0.486183, + "gen_feat_3": 501.39 + } + }, + { + "id": "t_transit_gen_4", + "task_id": "t_transit", + "provider_id": "p_gen_2", + "name": "Google Transit API (Gen p_gen_2)", + "features": { + "latency_ms": 463.1, + "cost_usd": 0.0, + "availability": 0.967212, + "gen_feat_1": 512.89, + "gen_feat_2": 0.512956, + "gen_feat_3": 495.23 + } + }, + { + "id": "t_transit_gen_5", + "task_id": "t_transit", + "provider_id": "p_gen_3", + "name": "Google Transit API (Gen p_gen_3)", + "features": { + "latency_ms": 456.23, + "cost_usd": 0.0, + "availability": 0.965992, + "gen_feat_1": 490.49, + "gen_feat_2": 0.508133, + "gen_feat_3": 504.92 + } + }, + { + "id": "t_transit_gen_6", + "task_id": "t_transit", + "provider_id": "p_gen_4", + "name": "Google Transit API (Gen p_gen_4)", + "features": { + "latency_ms": 440.18, + "cost_usd": 0.0, + "availability": 0.991733, + "gen_feat_1": 490.83, + "gen_feat_2": 0.504993, + "gen_feat_3": 492.89 + } + }, + { + "id": "t_transit_gen_7", + "task_id": "t_transit", + "provider_id": "p_gen_5", + "name": "Google Transit API (Gen p_gen_5)", + "features": { + "latency_ms": 462.92, + "cost_usd": 0.0, + "availability": 0.996902, + "gen_feat_1": 511.69, + "gen_feat_2": 0.506072, + "gen_feat_3": 487.84 + } + }, + { + "id": "t_transit_gen_8", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API (Gen p_google)", + "features": { + "latency_ms": 437.2, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 486.88, + "gen_feat_2": 0.486007, + "gen_feat_3": 512.05 + } + }, + { + "id": "t_transit_gen_9", + "task_id": "t_transit", + "provider_id": "p_amazon", + "name": "Google Transit API (Gen p_amazon)", + "features": { + "latency_ms": 454.11, + "cost_usd": 0.0, + "availability": 0.993251, + "gen_feat_1": 496.88, + "gen_feat_2": 0.494363, + "gen_feat_3": 508.7 + } + }, + { + "id": "t_archive_gen_2", + "task_id": "t_archive", + "provider_id": "p_unimib", + "name": "Archive.org API (Gen p_unimib)", + "features": { + "latency_ms": 491.38, + "cost_usd": 0.0, + "availability": 0.97419, + "gen_feat_1": 488.94, + "gen_feat_2": 0.490436, + "gen_feat_3": 502.27 + } + }, + { + "id": "t_archive_gen_3", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API (Gen p_archive)", + "features": { + "latency_ms": 493.0, + "cost_usd": 0.0, + "availability": 0.974135, + "gen_feat_1": 509.85, + "gen_feat_2": 0.501448, + "gen_feat_3": 508.14 + } + }, + { + "id": "t_archive_gen_4", + "task_id": "t_archive", + "provider_id": "p_local", + "name": "Archive.org API (Gen p_local)", + "features": { + "latency_ms": 506.7, + "cost_usd": 0.0, + "availability": 0.950007, + "gen_feat_1": 485.3, + "gen_feat_2": 0.506074, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_archive_gen_5", + "task_id": "t_archive", + "provider_id": "p_gen_1", + "name": "Archive.org API (Gen p_gen_1)", + "features": { + "latency_ms": 489.16, + "cost_usd": 0.0, + "availability": 0.997048, + "gen_feat_1": 498.8, + "gen_feat_2": 0.513697, + "gen_feat_3": 499.99 + } + }, + { + "id": "t_archive_gen_6", + "task_id": "t_archive", + "provider_id": "p_gen_2", + "name": "Archive.org API (Gen p_gen_2)", + "features": { + "latency_ms": 490.4, + "cost_usd": 0.0, + "availability": 0.989264, + "gen_feat_1": 499.32, + "gen_feat_2": 0.492021, + "gen_feat_3": 511.64 + } + }, + { + "id": "t_archive_gen_7", + "task_id": "t_archive", + "provider_id": "p_gen_3", + "name": "Archive.org API (Gen p_gen_3)", + "features": { + "latency_ms": 493.82, + "cost_usd": 0.0, + "availability": 0.963902, + "gen_feat_1": 513.54, + "gen_feat_2": 0.514704, + "gen_feat_3": 488.6 + } + }, + { + "id": "t_archive_gen_8", + "task_id": "t_archive", + "provider_id": "p_gen_4", + "name": "Archive.org API (Gen p_gen_4)", + "features": { + "latency_ms": 501.92, + "cost_usd": 0.0, + "availability": 0.987176, + "gen_feat_1": 487.31, + "gen_feat_2": 0.5052, + "gen_feat_3": 512.55 + } + }, + { + "id": "t_archive_gen_9", + "task_id": "t_archive", + "provider_id": "p_gen_5", + "name": "Archive.org API (Gen p_gen_5)", + "features": { + "latency_ms": 497.11, + "cost_usd": 0.0, + "availability": 0.959066, + "gen_feat_1": 489.18, + "gen_feat_2": 0.487091, + "gen_feat_3": 488.33 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_books", + "kind": "TASK", + "task_id": "t_books" + }, + { + "id": "n_parallel_options", + "kind": "AND", + "children": [ + { + "id": "n_amazon", + "kind": "TASK", + "task_id": "t_market" + }, + { + "id": "n_library_trip", + "kind": "SEQ", + "children": [ + { + "id": "n_opac", + "kind": "TASK", + "task_id": "t_library" + }, + { + "id": "n_geocode", + "kind": "TASK", + "task_id": "t_geocoding" + }, + { + "id": "n_transit", + "kind": "TASK", + "task_id": "t_transit" + } + ] + }, + { + "id": "n_archive", + "kind": "TASK", + "task_id": "t_archive" + } + ] + }, + { + "id": "n_report", + "kind": "ELEMENT", + "description": "Assemble final textbook access report" + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1357.94, + "hard": false + }, + { + "id": "gen_c_local_t_archive_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_archive" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_books", + "t_geocoding" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_archive", + "t_books" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/cremaschi2018-textbook-access_multi_hard.json b/experimentation/instances/cremaschi2018-textbook-access_multi_hard.json new file mode 100644 index 0000000..62c207a --- /dev/null +++ b/experimentation/instances/cremaschi2018-textbook-access_multi_hard.json @@ -0,0 +1,1196 @@ +{ + "metadata": { + "id": "cremaschi2018-textbook-access_multi_hard", + "name": "Book info retrieval (Cremaschi et al. 2018) [multi, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "QoS-aware instance derived from the running example in 'A Practical Approach to Services Composition Through Light Semantic Descriptions' (ESOCC 2018). QoS values are illustrative placeholders.", + "paper": { + "title": "A Practical Approach to Services Composition Through Light Semantic Descriptions", + "authors": "M. Cremaschi et al.", + "year": 2018, + "doi": "10.1007/978-3-319-99819-0_10" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Monetary cost per execution", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10 + } + }, + { + "id": "availability", + "name": "Service availability", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_google", + "name": "Google" + }, + { + "id": "p_amazon", + "name": "Amazon" + }, + { + "id": "p_unimib", + "name": "University of Milan - Bicocca (OPAC library)" + }, + { + "id": "p_archive", + "name": "Archive.org" + }, + { + "id": "p_local", + "name": "Local Application" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_books", + "name": "Retrieve book metadata from title (ISBN/author/title)" + }, + { + "id": "t_market", + "name": "Check e-commerce availability/price by ISBN" + }, + { + "id": "t_library", + "name": "Check library availability and retrieve library address" + }, + { + "id": "t_geocoding", + "name": "Geocode library address into coordinates" + }, + { + "id": "t_transit", + "name": "Retrieve public transport options to the library" + }, + { + "id": "t_archive", + "name": "Check free eBook availability (Archive.org)" + } + ], + "candidates": [ + { + "id": "c_google_books_api", + "task_id": "t_books", + "provider_id": "p_google", + "name": "Google Books API", + "features": { + "latency_ms": 250, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_amazon_market_api", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API", + "features": { + "latency_ms": 400, + "cost_usd": 0.001, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_opac_library_api", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API", + "features": { + "latency_ms": 350, + "cost_usd": 0.0001, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_geocoding_api", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API", + "features": { + "latency_ms": 300, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_transit_api", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API", + "features": { + "latency_ms": 450, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_archive_api", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API", + "features": { + "latency_ms": 500, + "cost_usd": 0.0001, + "availability": 0.97, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_books_gen_1", + "task_id": "t_books", + "provider_id": "p_gen_shared", + "name": "Google Books API (Gen Shared)", + "features": { + "latency_ms": 250.27, + "cost_usd": 0.0, + "availability": 0.970656, + "gen_feat_1": 507.35, + "gen_feat_2": 0.498346, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_market_gen_1", + "task_id": "t_market", + "provider_id": "p_gen_shared", + "name": "Amazon Market API (Gen Shared)", + "features": { + "latency_ms": 410.3, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.37, + "gen_feat_2": 0.4873, + "gen_feat_3": 499.78 + } + }, + { + "id": "t_library_gen_1", + "task_id": "t_library", + "provider_id": "p_gen_shared", + "name": "OPAC Library API (Gen Shared)", + "features": { + "latency_ms": 350.22, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 503.36, + "gen_feat_2": 0.490142, + "gen_feat_3": 513.01 + } + }, + { + "id": "t_geocoding_gen_1", + "task_id": "t_geocoding", + "provider_id": "p_gen_shared", + "name": "Google Maps Geocoding API (Gen Shared)", + "features": { + "latency_ms": 299.52, + "cost_usd": 0.0, + "availability": 0.970921, + "gen_feat_1": 509.42, + "gen_feat_2": 0.491433, + "gen_feat_3": 503.84 + } + }, + { + "id": "t_transit_gen_1", + "task_id": "t_transit", + "provider_id": "p_gen_shared", + "name": "Google Transit API (Gen Shared)", + "features": { + "latency_ms": 457.93, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.8, + "gen_feat_2": 0.5146, + "gen_feat_3": 509.74 + } + }, + { + "id": "t_archive_gen_1", + "task_id": "t_archive", + "provider_id": "p_gen_shared", + "name": "Archive.org API (Gen Shared)", + "features": { + "latency_ms": 494.4, + "cost_usd": 0.0, + "availability": 0.973217, + "gen_feat_1": 486.21, + "gen_feat_2": 0.487758, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_books_gen_2", + "task_id": "t_books", + "provider_id": "p_unimib", + "name": "Google Books API (Gen p_unimib)", + "features": { + "latency_ms": 251.51, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.43, + "gen_feat_2": 0.49659, + "gen_feat_3": 492.56 + } + }, + { + "id": "t_books_gen_3", + "task_id": "t_books", + "provider_id": "p_archive", + "name": "Google Books API (Gen p_archive)", + "features": { + "latency_ms": 253.59, + "cost_usd": 0.0, + "availability": 0.976832, + "gen_feat_1": 498.31, + "gen_feat_2": 0.504989, + "gen_feat_3": 485.73 + } + }, + { + "id": "t_books_gen_4", + "task_id": "t_books", + "provider_id": "p_local", + "name": "Google Books API (Gen p_local)", + "features": { + "latency_ms": 253.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 496.81, + "gen_feat_2": 0.509742, + "gen_feat_3": 503.82 + } + }, + { + "id": "t_books_gen_5", + "task_id": "t_books", + "provider_id": "p_gen_1", + "name": "Google Books API (Gen p_gen_1)", + "features": { + "latency_ms": 243.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.29, + "gen_feat_2": 0.497801, + "gen_feat_3": 491.8 + } + }, + { + "id": "t_books_gen_6", + "task_id": "t_books", + "provider_id": "p_gen_2", + "name": "Google Books API (Gen p_gen_2)", + "features": { + "latency_ms": 249.33, + "cost_usd": 0.0, + "availability": 0.968324, + "gen_feat_1": 500.1, + "gen_feat_2": 0.489322, + "gen_feat_3": 486.96 + } + }, + { + "id": "t_books_gen_7", + "task_id": "t_books", + "provider_id": "p_gen_3", + "name": "Google Books API (Gen p_gen_3)", + "features": { + "latency_ms": 244.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.49, + "gen_feat_2": 0.509901, + "gen_feat_3": 510.32 + } + }, + { + "id": "t_books_gen_8", + "task_id": "t_books", + "provider_id": "p_gen_4", + "name": "Google Books API (Gen p_gen_4)", + "features": { + "latency_ms": 249.93, + "cost_usd": 0.0, + "availability": 0.984683, + "gen_feat_1": 503.61, + "gen_feat_2": 0.501017, + "gen_feat_3": 501.49 + } + }, + { + "id": "t_books_gen_9", + "task_id": "t_books", + "provider_id": "p_gen_5", + "name": "Google Books API (Gen p_gen_5)", + "features": { + "latency_ms": 252.75, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 505.53, + "gen_feat_2": 0.491572, + "gen_feat_3": 506.63 + } + }, + { + "id": "t_market_gen_2", + "task_id": "t_market", + "provider_id": "p_google", + "name": "Amazon Market API (Gen p_google)", + "features": { + "latency_ms": 390.51, + "cost_usd": 0.0, + "availability": 0.974193, + "gen_feat_1": 514.03, + "gen_feat_2": 0.504606, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_market_gen_3", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API (Gen p_amazon)", + "features": { + "latency_ms": 390.29, + "cost_usd": 0.0, + "availability": 0.964065, + "gen_feat_1": 490.39, + "gen_feat_2": 0.510618, + "gen_feat_3": 500.06 + } + }, + { + "id": "t_market_gen_4", + "task_id": "t_market", + "provider_id": "p_unimib", + "name": "Amazon Market API (Gen p_unimib)", + "features": { + "latency_ms": 403.22, + "cost_usd": 0.0, + "availability": 0.98629, + "gen_feat_1": 506.11, + "gen_feat_2": 0.504836, + "gen_feat_3": 513.95 + } + }, + { + "id": "t_market_gen_5", + "task_id": "t_market", + "provider_id": "p_archive", + "name": "Amazon Market API (Gen p_archive)", + "features": { + "latency_ms": 392.94, + "cost_usd": 0.0, + "availability": 0.963527, + "gen_feat_1": 512.48, + "gen_feat_2": 0.514296, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_market_gen_6", + "task_id": "t_market", + "provider_id": "p_local", + "name": "Amazon Market API (Gen p_local)", + "features": { + "latency_ms": 393.03, + "cost_usd": 0.0, + "availability": 0.981369, + "gen_feat_1": 488.34, + "gen_feat_2": 0.514668, + "gen_feat_3": 505.0 + } + }, + { + "id": "t_market_gen_7", + "task_id": "t_market", + "provider_id": "p_gen_1", + "name": "Amazon Market API (Gen p_gen_1)", + "features": { + "latency_ms": 411.7, + "cost_usd": 0.0, + "availability": 0.985823, + "gen_feat_1": 500.86, + "gen_feat_2": 0.497755, + "gen_feat_3": 497.03 + } + }, + { + "id": "t_market_gen_8", + "task_id": "t_market", + "provider_id": "p_gen_2", + "name": "Amazon Market API (Gen p_gen_2)", + "features": { + "latency_ms": 402.71, + "cost_usd": 0.0, + "availability": 0.991509, + "gen_feat_1": 505.13, + "gen_feat_2": 0.49775, + "gen_feat_3": 491.63 + } + }, + { + "id": "t_market_gen_9", + "task_id": "t_market", + "provider_id": "p_gen_3", + "name": "Amazon Market API (Gen p_gen_3)", + "features": { + "latency_ms": 402.55, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 510.3, + "gen_feat_2": 0.501032, + "gen_feat_3": 505.68 + } + }, + { + "id": "t_library_gen_2", + "task_id": "t_library", + "provider_id": "p_gen_4", + "name": "OPAC Library API (Gen p_gen_4)", + "features": { + "latency_ms": 345.85, + "cost_usd": 0.0, + "availability": 0.97661, + "gen_feat_1": 508.48, + "gen_feat_2": 0.509068, + "gen_feat_3": 505.91 + } + }, + { + "id": "t_library_gen_3", + "task_id": "t_library", + "provider_id": "p_gen_5", + "name": "OPAC Library API (Gen p_gen_5)", + "features": { + "latency_ms": 357.65, + "cost_usd": 0.0, + "availability": 0.995668, + "gen_feat_1": 511.52, + "gen_feat_2": 0.489245, + "gen_feat_3": 489.95 + } + }, + { + "id": "t_library_gen_4", + "task_id": "t_library", + "provider_id": "p_google", + "name": "OPAC Library API (Gen p_google)", + "features": { + "latency_ms": 347.46, + "cost_usd": 0.0, + "availability": 0.961356, + "gen_feat_1": 510.48, + "gen_feat_2": 0.509522, + "gen_feat_3": 510.51 + } + }, + { + "id": "t_library_gen_5", + "task_id": "t_library", + "provider_id": "p_amazon", + "name": "OPAC Library API (Gen p_amazon)", + "features": { + "latency_ms": 346.07, + "cost_usd": 0.0, + "availability": 0.99049, + "gen_feat_1": 510.53, + "gen_feat_2": 0.488512, + "gen_feat_3": 513.85 + } + }, + { + "id": "t_library_gen_6", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API (Gen p_unimib)", + "features": { + "latency_ms": 353.12, + "cost_usd": 0.0, + "availability": 0.966548, + "gen_feat_1": 500.27, + "gen_feat_2": 0.497436, + "gen_feat_3": 511.73 + } + }, + { + "id": "t_library_gen_7", + "task_id": "t_library", + "provider_id": "p_archive", + "name": "OPAC Library API (Gen p_archive)", + "features": { + "latency_ms": 356.85, + "cost_usd": 0.0, + "availability": 0.993546, + "gen_feat_1": 510.3, + "gen_feat_2": 0.513619, + "gen_feat_3": 511.4 + } + }, + { + "id": "t_library_gen_8", + "task_id": "t_library", + "provider_id": "p_local", + "name": "OPAC Library API (Gen p_local)", + "features": { + "latency_ms": 357.15, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.06, + "gen_feat_2": 0.487388, + "gen_feat_3": 498.18 + } + }, + { + "id": "t_library_gen_9", + "task_id": "t_library", + "provider_id": "p_gen_1", + "name": "OPAC Library API (Gen p_gen_1)", + "features": { + "latency_ms": 355.46, + "cost_usd": 0.0, + "availability": 0.970169, + "gen_feat_1": 490.3, + "gen_feat_2": 0.497807, + "gen_feat_3": 495.16 + } + }, + { + "id": "t_geocoding_gen_2", + "task_id": "t_geocoding", + "provider_id": "p_gen_2", + "name": "Google Maps Geocoding API (Gen p_gen_2)", + "features": { + "latency_ms": 293.3, + "cost_usd": 0.0, + "availability": 0.974652, + "gen_feat_1": 508.37, + "gen_feat_2": 0.500348, + "gen_feat_3": 495.48 + } + }, + { + "id": "t_geocoding_gen_3", + "task_id": "t_geocoding", + "provider_id": "p_gen_3", + "name": "Google Maps Geocoding API (Gen p_gen_3)", + "features": { + "latency_ms": 298.14, + "cost_usd": 0.0, + "availability": 0.985441, + "gen_feat_1": 501.06, + "gen_feat_2": 0.508714, + "gen_feat_3": 511.67 + } + }, + { + "id": "t_geocoding_gen_4", + "task_id": "t_geocoding", + "provider_id": "p_gen_4", + "name": "Google Maps Geocoding API (Gen p_gen_4)", + "features": { + "latency_ms": 296.31, + "cost_usd": 0.0, + "availability": 0.970937, + "gen_feat_1": 504.66, + "gen_feat_2": 0.485959, + "gen_feat_3": 506.47 + } + }, + { + "id": "t_geocoding_gen_5", + "task_id": "t_geocoding", + "provider_id": "p_gen_5", + "name": "Google Maps Geocoding API (Gen p_gen_5)", + "features": { + "latency_ms": 292.44, + "cost_usd": 0.0, + "availability": 0.970116, + "gen_feat_1": 506.54, + "gen_feat_2": 0.485388, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_geocoding_gen_6", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API (Gen p_google)", + "features": { + "latency_ms": 296.68, + "cost_usd": 0.0, + "availability": 0.979126, + "gen_feat_1": 503.49, + "gen_feat_2": 0.509299, + "gen_feat_3": 501.7 + } + }, + { + "id": "t_geocoding_gen_7", + "task_id": "t_geocoding", + "provider_id": "p_amazon", + "name": "Google Maps Geocoding API (Gen p_amazon)", + "features": { + "latency_ms": 299.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.43, + "gen_feat_2": 0.485447, + "gen_feat_3": 504.86 + } + }, + { + "id": "t_geocoding_gen_8", + "task_id": "t_geocoding", + "provider_id": "p_unimib", + "name": "Google Maps Geocoding API (Gen p_unimib)", + "features": { + "latency_ms": 291.86, + "cost_usd": 0.0, + "availability": 0.967929, + "gen_feat_1": 500.94, + "gen_feat_2": 0.487602, + "gen_feat_3": 501.12 + } + }, + { + "id": "t_geocoding_gen_9", + "task_id": "t_geocoding", + "provider_id": "p_archive", + "name": "Google Maps Geocoding API (Gen p_archive)", + "features": { + "latency_ms": 303.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.48, + "gen_feat_2": 0.494252, + "gen_feat_3": 501.53 + } + }, + { + "id": "t_transit_gen_2", + "task_id": "t_transit", + "provider_id": "p_local", + "name": "Google Transit API (Gen p_local)", + "features": { + "latency_ms": 447.81, + "cost_usd": 0.0, + "availability": 0.97876, + "gen_feat_1": 487.34, + "gen_feat_2": 0.494893, + "gen_feat_3": 492.66 + } + }, + { + "id": "t_transit_gen_3", + "task_id": "t_transit", + "provider_id": "p_gen_1", + "name": "Google Transit API (Gen p_gen_1)", + "features": { + "latency_ms": 454.73, + "cost_usd": 0.0, + "availability": 0.982378, + "gen_feat_1": 508.31, + "gen_feat_2": 0.486183, + "gen_feat_3": 501.39 + } + }, + { + "id": "t_transit_gen_4", + "task_id": "t_transit", + "provider_id": "p_gen_2", + "name": "Google Transit API (Gen p_gen_2)", + "features": { + "latency_ms": 463.1, + "cost_usd": 0.0, + "availability": 0.967212, + "gen_feat_1": 512.89, + "gen_feat_2": 0.512956, + "gen_feat_3": 495.23 + } + }, + { + "id": "t_transit_gen_5", + "task_id": "t_transit", + "provider_id": "p_gen_3", + "name": "Google Transit API (Gen p_gen_3)", + "features": { + "latency_ms": 456.23, + "cost_usd": 0.0, + "availability": 0.965992, + "gen_feat_1": 490.49, + "gen_feat_2": 0.508133, + "gen_feat_3": 504.92 + } + }, + { + "id": "t_transit_gen_6", + "task_id": "t_transit", + "provider_id": "p_gen_4", + "name": "Google Transit API (Gen p_gen_4)", + "features": { + "latency_ms": 440.18, + "cost_usd": 0.0, + "availability": 0.991733, + "gen_feat_1": 490.83, + "gen_feat_2": 0.504993, + "gen_feat_3": 492.89 + } + }, + { + "id": "t_transit_gen_7", + "task_id": "t_transit", + "provider_id": "p_gen_5", + "name": "Google Transit API (Gen p_gen_5)", + "features": { + "latency_ms": 462.92, + "cost_usd": 0.0, + "availability": 0.996902, + "gen_feat_1": 511.69, + "gen_feat_2": 0.506072, + "gen_feat_3": 487.84 + } + }, + { + "id": "t_transit_gen_8", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API (Gen p_google)", + "features": { + "latency_ms": 437.2, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 486.88, + "gen_feat_2": 0.486007, + "gen_feat_3": 512.05 + } + }, + { + "id": "t_transit_gen_9", + "task_id": "t_transit", + "provider_id": "p_amazon", + "name": "Google Transit API (Gen p_amazon)", + "features": { + "latency_ms": 454.11, + "cost_usd": 0.0, + "availability": 0.993251, + "gen_feat_1": 496.88, + "gen_feat_2": 0.494363, + "gen_feat_3": 508.7 + } + }, + { + "id": "t_archive_gen_2", + "task_id": "t_archive", + "provider_id": "p_unimib", + "name": "Archive.org API (Gen p_unimib)", + "features": { + "latency_ms": 491.38, + "cost_usd": 0.0, + "availability": 0.97419, + "gen_feat_1": 488.94, + "gen_feat_2": 0.490436, + "gen_feat_3": 502.27 + } + }, + { + "id": "t_archive_gen_3", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API (Gen p_archive)", + "features": { + "latency_ms": 493.0, + "cost_usd": 0.0, + "availability": 0.974135, + "gen_feat_1": 509.85, + "gen_feat_2": 0.501448, + "gen_feat_3": 508.14 + } + }, + { + "id": "t_archive_gen_4", + "task_id": "t_archive", + "provider_id": "p_local", + "name": "Archive.org API (Gen p_local)", + "features": { + "latency_ms": 506.7, + "cost_usd": 0.0, + "availability": 0.950007, + "gen_feat_1": 485.3, + "gen_feat_2": 0.506074, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_archive_gen_5", + "task_id": "t_archive", + "provider_id": "p_gen_1", + "name": "Archive.org API (Gen p_gen_1)", + "features": { + "latency_ms": 489.16, + "cost_usd": 0.0, + "availability": 0.997048, + "gen_feat_1": 498.8, + "gen_feat_2": 0.513697, + "gen_feat_3": 499.99 + } + }, + { + "id": "t_archive_gen_6", + "task_id": "t_archive", + "provider_id": "p_gen_2", + "name": "Archive.org API (Gen p_gen_2)", + "features": { + "latency_ms": 490.4, + "cost_usd": 0.0, + "availability": 0.989264, + "gen_feat_1": 499.32, + "gen_feat_2": 0.492021, + "gen_feat_3": 511.64 + } + }, + { + "id": "t_archive_gen_7", + "task_id": "t_archive", + "provider_id": "p_gen_3", + "name": "Archive.org API (Gen p_gen_3)", + "features": { + "latency_ms": 493.82, + "cost_usd": 0.0, + "availability": 0.963902, + "gen_feat_1": 513.54, + "gen_feat_2": 0.514704, + "gen_feat_3": 488.6 + } + }, + { + "id": "t_archive_gen_8", + "task_id": "t_archive", + "provider_id": "p_gen_4", + "name": "Archive.org API (Gen p_gen_4)", + "features": { + "latency_ms": 501.92, + "cost_usd": 0.0, + "availability": 0.987176, + "gen_feat_1": 487.31, + "gen_feat_2": 0.5052, + "gen_feat_3": 512.55 + } + }, + { + "id": "t_archive_gen_9", + "task_id": "t_archive", + "provider_id": "p_gen_5", + "name": "Archive.org API (Gen p_gen_5)", + "features": { + "latency_ms": 497.11, + "cost_usd": 0.0, + "availability": 0.959066, + "gen_feat_1": 489.18, + "gen_feat_2": 0.487091, + "gen_feat_3": 488.33 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_books", + "kind": "TASK", + "task_id": "t_books" + }, + { + "id": "n_parallel_options", + "kind": "AND", + "children": [ + { + "id": "n_amazon", + "kind": "TASK", + "task_id": "t_market" + }, + { + "id": "n_library_trip", + "kind": "SEQ", + "children": [ + { + "id": "n_opac", + "kind": "TASK", + "task_id": "t_library" + }, + { + "id": "n_geocode", + "kind": "TASK", + "task_id": "t_geocoding" + }, + { + "id": "n_transit", + "kind": "TASK", + "task_id": "t_transit" + } + ] + }, + { + "id": "n_archive", + "kind": "TASK", + "task_id": "t_archive" + } + ] + }, + { + "id": "n_report", + "kind": "ELEMENT", + "description": "Assemble final textbook access report" + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MULTI", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1" + ], + "weights": { + "availability": 0.34, + "cost_usd": 0.33, + "gen_feat_1": 0.33 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1357.94, + "hard": true + }, + { + "id": "gen_c_local_t_archive_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_archive" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_books", + "t_geocoding" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_archive", + "t_books" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/cremaschi2018-textbook-access_multi_soft.json b/experimentation/instances/cremaschi2018-textbook-access_multi_soft.json new file mode 100644 index 0000000..1015653 --- /dev/null +++ b/experimentation/instances/cremaschi2018-textbook-access_multi_soft.json @@ -0,0 +1,1196 @@ +{ + "metadata": { + "id": "cremaschi2018-textbook-access_multi_soft", + "name": "Book info retrieval (Cremaschi et al. 2018) [multi, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "QoS-aware instance derived from the running example in 'A Practical Approach to Services Composition Through Light Semantic Descriptions' (ESOCC 2018). QoS values are illustrative placeholders.", + "paper": { + "title": "A Practical Approach to Services Composition Through Light Semantic Descriptions", + "authors": "M. Cremaschi et al.", + "year": 2018, + "doi": "10.1007/978-3-319-99819-0_10" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end latency", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10000 + } + }, + { + "id": "cost_usd", + "name": "Monetary cost per execution", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 10 + } + }, + { + "id": "availability", + "name": "Service availability", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_google", + "name": "Google" + }, + { + "id": "p_amazon", + "name": "Amazon" + }, + { + "id": "p_unimib", + "name": "University of Milan - Bicocca (OPAC library)" + }, + { + "id": "p_archive", + "name": "Archive.org" + }, + { + "id": "p_local", + "name": "Local Application" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_books", + "name": "Retrieve book metadata from title (ISBN/author/title)" + }, + { + "id": "t_market", + "name": "Check e-commerce availability/price by ISBN" + }, + { + "id": "t_library", + "name": "Check library availability and retrieve library address" + }, + { + "id": "t_geocoding", + "name": "Geocode library address into coordinates" + }, + { + "id": "t_transit", + "name": "Retrieve public transport options to the library" + }, + { + "id": "t_archive", + "name": "Check free eBook availability (Archive.org)" + } + ], + "candidates": [ + { + "id": "c_google_books_api", + "task_id": "t_books", + "provider_id": "p_google", + "name": "Google Books API", + "features": { + "latency_ms": 250, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_amazon_market_api", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API", + "features": { + "latency_ms": 400, + "cost_usd": 0.001, + "availability": 0.99, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_opac_library_api", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API", + "features": { + "latency_ms": 350, + "cost_usd": 0.0001, + "availability": 0.98, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_geocoding_api", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API", + "features": { + "latency_ms": 300, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_google_transit_api", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API", + "features": { + "latency_ms": 450, + "cost_usd": 0.0001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_archive_api", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API", + "features": { + "latency_ms": 500, + "cost_usd": 0.0001, + "availability": 0.97, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_books_gen_1", + "task_id": "t_books", + "provider_id": "p_gen_shared", + "name": "Google Books API (Gen Shared)", + "features": { + "latency_ms": 250.27, + "cost_usd": 0.0, + "availability": 0.970656, + "gen_feat_1": 507.35, + "gen_feat_2": 0.498346, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_market_gen_1", + "task_id": "t_market", + "provider_id": "p_gen_shared", + "name": "Amazon Market API (Gen Shared)", + "features": { + "latency_ms": 410.3, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.37, + "gen_feat_2": 0.4873, + "gen_feat_3": 499.78 + } + }, + { + "id": "t_library_gen_1", + "task_id": "t_library", + "provider_id": "p_gen_shared", + "name": "OPAC Library API (Gen Shared)", + "features": { + "latency_ms": 350.22, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 503.36, + "gen_feat_2": 0.490142, + "gen_feat_3": 513.01 + } + }, + { + "id": "t_geocoding_gen_1", + "task_id": "t_geocoding", + "provider_id": "p_gen_shared", + "name": "Google Maps Geocoding API (Gen Shared)", + "features": { + "latency_ms": 299.52, + "cost_usd": 0.0, + "availability": 0.970921, + "gen_feat_1": 509.42, + "gen_feat_2": 0.491433, + "gen_feat_3": 503.84 + } + }, + { + "id": "t_transit_gen_1", + "task_id": "t_transit", + "provider_id": "p_gen_shared", + "name": "Google Transit API (Gen Shared)", + "features": { + "latency_ms": 457.93, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.8, + "gen_feat_2": 0.5146, + "gen_feat_3": 509.74 + } + }, + { + "id": "t_archive_gen_1", + "task_id": "t_archive", + "provider_id": "p_gen_shared", + "name": "Archive.org API (Gen Shared)", + "features": { + "latency_ms": 494.4, + "cost_usd": 0.0, + "availability": 0.973217, + "gen_feat_1": 486.21, + "gen_feat_2": 0.487758, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_books_gen_2", + "task_id": "t_books", + "provider_id": "p_unimib", + "name": "Google Books API (Gen p_unimib)", + "features": { + "latency_ms": 251.51, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 494.43, + "gen_feat_2": 0.49659, + "gen_feat_3": 492.56 + } + }, + { + "id": "t_books_gen_3", + "task_id": "t_books", + "provider_id": "p_archive", + "name": "Google Books API (Gen p_archive)", + "features": { + "latency_ms": 253.59, + "cost_usd": 0.0, + "availability": 0.976832, + "gen_feat_1": 498.31, + "gen_feat_2": 0.504989, + "gen_feat_3": 485.73 + } + }, + { + "id": "t_books_gen_4", + "task_id": "t_books", + "provider_id": "p_local", + "name": "Google Books API (Gen p_local)", + "features": { + "latency_ms": 253.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 496.81, + "gen_feat_2": 0.509742, + "gen_feat_3": 503.82 + } + }, + { + "id": "t_books_gen_5", + "task_id": "t_books", + "provider_id": "p_gen_1", + "name": "Google Books API (Gen p_gen_1)", + "features": { + "latency_ms": 243.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.29, + "gen_feat_2": 0.497801, + "gen_feat_3": 491.8 + } + }, + { + "id": "t_books_gen_6", + "task_id": "t_books", + "provider_id": "p_gen_2", + "name": "Google Books API (Gen p_gen_2)", + "features": { + "latency_ms": 249.33, + "cost_usd": 0.0, + "availability": 0.968324, + "gen_feat_1": 500.1, + "gen_feat_2": 0.489322, + "gen_feat_3": 486.96 + } + }, + { + "id": "t_books_gen_7", + "task_id": "t_books", + "provider_id": "p_gen_3", + "name": "Google Books API (Gen p_gen_3)", + "features": { + "latency_ms": 244.56, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 498.49, + "gen_feat_2": 0.509901, + "gen_feat_3": 510.32 + } + }, + { + "id": "t_books_gen_8", + "task_id": "t_books", + "provider_id": "p_gen_4", + "name": "Google Books API (Gen p_gen_4)", + "features": { + "latency_ms": 249.93, + "cost_usd": 0.0, + "availability": 0.984683, + "gen_feat_1": 503.61, + "gen_feat_2": 0.501017, + "gen_feat_3": 501.49 + } + }, + { + "id": "t_books_gen_9", + "task_id": "t_books", + "provider_id": "p_gen_5", + "name": "Google Books API (Gen p_gen_5)", + "features": { + "latency_ms": 252.75, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 505.53, + "gen_feat_2": 0.491572, + "gen_feat_3": 506.63 + } + }, + { + "id": "t_market_gen_2", + "task_id": "t_market", + "provider_id": "p_google", + "name": "Amazon Market API (Gen p_google)", + "features": { + "latency_ms": 390.51, + "cost_usd": 0.0, + "availability": 0.974193, + "gen_feat_1": 514.03, + "gen_feat_2": 0.504606, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_market_gen_3", + "task_id": "t_market", + "provider_id": "p_amazon", + "name": "Amazon Market API (Gen p_amazon)", + "features": { + "latency_ms": 390.29, + "cost_usd": 0.0, + "availability": 0.964065, + "gen_feat_1": 490.39, + "gen_feat_2": 0.510618, + "gen_feat_3": 500.06 + } + }, + { + "id": "t_market_gen_4", + "task_id": "t_market", + "provider_id": "p_unimib", + "name": "Amazon Market API (Gen p_unimib)", + "features": { + "latency_ms": 403.22, + "cost_usd": 0.0, + "availability": 0.98629, + "gen_feat_1": 506.11, + "gen_feat_2": 0.504836, + "gen_feat_3": 513.95 + } + }, + { + "id": "t_market_gen_5", + "task_id": "t_market", + "provider_id": "p_archive", + "name": "Amazon Market API (Gen p_archive)", + "features": { + "latency_ms": 392.94, + "cost_usd": 0.0, + "availability": 0.963527, + "gen_feat_1": 512.48, + "gen_feat_2": 0.514296, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_market_gen_6", + "task_id": "t_market", + "provider_id": "p_local", + "name": "Amazon Market API (Gen p_local)", + "features": { + "latency_ms": 393.03, + "cost_usd": 0.0, + "availability": 0.981369, + "gen_feat_1": 488.34, + "gen_feat_2": 0.514668, + "gen_feat_3": 505.0 + } + }, + { + "id": "t_market_gen_7", + "task_id": "t_market", + "provider_id": "p_gen_1", + "name": "Amazon Market API (Gen p_gen_1)", + "features": { + "latency_ms": 411.7, + "cost_usd": 0.0, + "availability": 0.985823, + "gen_feat_1": 500.86, + "gen_feat_2": 0.497755, + "gen_feat_3": 497.03 + } + }, + { + "id": "t_market_gen_8", + "task_id": "t_market", + "provider_id": "p_gen_2", + "name": "Amazon Market API (Gen p_gen_2)", + "features": { + "latency_ms": 402.71, + "cost_usd": 0.0, + "availability": 0.991509, + "gen_feat_1": 505.13, + "gen_feat_2": 0.49775, + "gen_feat_3": 491.63 + } + }, + { + "id": "t_market_gen_9", + "task_id": "t_market", + "provider_id": "p_gen_3", + "name": "Amazon Market API (Gen p_gen_3)", + "features": { + "latency_ms": 402.55, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 510.3, + "gen_feat_2": 0.501032, + "gen_feat_3": 505.68 + } + }, + { + "id": "t_library_gen_2", + "task_id": "t_library", + "provider_id": "p_gen_4", + "name": "OPAC Library API (Gen p_gen_4)", + "features": { + "latency_ms": 345.85, + "cost_usd": 0.0, + "availability": 0.97661, + "gen_feat_1": 508.48, + "gen_feat_2": 0.509068, + "gen_feat_3": 505.91 + } + }, + { + "id": "t_library_gen_3", + "task_id": "t_library", + "provider_id": "p_gen_5", + "name": "OPAC Library API (Gen p_gen_5)", + "features": { + "latency_ms": 357.65, + "cost_usd": 0.0, + "availability": 0.995668, + "gen_feat_1": 511.52, + "gen_feat_2": 0.489245, + "gen_feat_3": 489.95 + } + }, + { + "id": "t_library_gen_4", + "task_id": "t_library", + "provider_id": "p_google", + "name": "OPAC Library API (Gen p_google)", + "features": { + "latency_ms": 347.46, + "cost_usd": 0.0, + "availability": 0.961356, + "gen_feat_1": 510.48, + "gen_feat_2": 0.509522, + "gen_feat_3": 510.51 + } + }, + { + "id": "t_library_gen_5", + "task_id": "t_library", + "provider_id": "p_amazon", + "name": "OPAC Library API (Gen p_amazon)", + "features": { + "latency_ms": 346.07, + "cost_usd": 0.0, + "availability": 0.99049, + "gen_feat_1": 510.53, + "gen_feat_2": 0.488512, + "gen_feat_3": 513.85 + } + }, + { + "id": "t_library_gen_6", + "task_id": "t_library", + "provider_id": "p_unimib", + "name": "OPAC Library API (Gen p_unimib)", + "features": { + "latency_ms": 353.12, + "cost_usd": 0.0, + "availability": 0.966548, + "gen_feat_1": 500.27, + "gen_feat_2": 0.497436, + "gen_feat_3": 511.73 + } + }, + { + "id": "t_library_gen_7", + "task_id": "t_library", + "provider_id": "p_archive", + "name": "OPAC Library API (Gen p_archive)", + "features": { + "latency_ms": 356.85, + "cost_usd": 0.0, + "availability": 0.993546, + "gen_feat_1": 510.3, + "gen_feat_2": 0.513619, + "gen_feat_3": 511.4 + } + }, + { + "id": "t_library_gen_8", + "task_id": "t_library", + "provider_id": "p_local", + "name": "OPAC Library API (Gen p_local)", + "features": { + "latency_ms": 357.15, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 485.06, + "gen_feat_2": 0.487388, + "gen_feat_3": 498.18 + } + }, + { + "id": "t_library_gen_9", + "task_id": "t_library", + "provider_id": "p_gen_1", + "name": "OPAC Library API (Gen p_gen_1)", + "features": { + "latency_ms": 355.46, + "cost_usd": 0.0, + "availability": 0.970169, + "gen_feat_1": 490.3, + "gen_feat_2": 0.497807, + "gen_feat_3": 495.16 + } + }, + { + "id": "t_geocoding_gen_2", + "task_id": "t_geocoding", + "provider_id": "p_gen_2", + "name": "Google Maps Geocoding API (Gen p_gen_2)", + "features": { + "latency_ms": 293.3, + "cost_usd": 0.0, + "availability": 0.974652, + "gen_feat_1": 508.37, + "gen_feat_2": 0.500348, + "gen_feat_3": 495.48 + } + }, + { + "id": "t_geocoding_gen_3", + "task_id": "t_geocoding", + "provider_id": "p_gen_3", + "name": "Google Maps Geocoding API (Gen p_gen_3)", + "features": { + "latency_ms": 298.14, + "cost_usd": 0.0, + "availability": 0.985441, + "gen_feat_1": 501.06, + "gen_feat_2": 0.508714, + "gen_feat_3": 511.67 + } + }, + { + "id": "t_geocoding_gen_4", + "task_id": "t_geocoding", + "provider_id": "p_gen_4", + "name": "Google Maps Geocoding API (Gen p_gen_4)", + "features": { + "latency_ms": 296.31, + "cost_usd": 0.0, + "availability": 0.970937, + "gen_feat_1": 504.66, + "gen_feat_2": 0.485959, + "gen_feat_3": 506.47 + } + }, + { + "id": "t_geocoding_gen_5", + "task_id": "t_geocoding", + "provider_id": "p_gen_5", + "name": "Google Maps Geocoding API (Gen p_gen_5)", + "features": { + "latency_ms": 292.44, + "cost_usd": 0.0, + "availability": 0.970116, + "gen_feat_1": 506.54, + "gen_feat_2": 0.485388, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_geocoding_gen_6", + "task_id": "t_geocoding", + "provider_id": "p_google", + "name": "Google Maps Geocoding API (Gen p_google)", + "features": { + "latency_ms": 296.68, + "cost_usd": 0.0, + "availability": 0.979126, + "gen_feat_1": 503.49, + "gen_feat_2": 0.509299, + "gen_feat_3": 501.7 + } + }, + { + "id": "t_geocoding_gen_7", + "task_id": "t_geocoding", + "provider_id": "p_amazon", + "name": "Google Maps Geocoding API (Gen p_amazon)", + "features": { + "latency_ms": 299.92, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 492.43, + "gen_feat_2": 0.485447, + "gen_feat_3": 504.86 + } + }, + { + "id": "t_geocoding_gen_8", + "task_id": "t_geocoding", + "provider_id": "p_unimib", + "name": "Google Maps Geocoding API (Gen p_unimib)", + "features": { + "latency_ms": 291.86, + "cost_usd": 0.0, + "availability": 0.967929, + "gen_feat_1": 500.94, + "gen_feat_2": 0.487602, + "gen_feat_3": 501.12 + } + }, + { + "id": "t_geocoding_gen_9", + "task_id": "t_geocoding", + "provider_id": "p_archive", + "name": "Google Maps Geocoding API (Gen p_archive)", + "features": { + "latency_ms": 303.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.48, + "gen_feat_2": 0.494252, + "gen_feat_3": 501.53 + } + }, + { + "id": "t_transit_gen_2", + "task_id": "t_transit", + "provider_id": "p_local", + "name": "Google Transit API (Gen p_local)", + "features": { + "latency_ms": 447.81, + "cost_usd": 0.0, + "availability": 0.97876, + "gen_feat_1": 487.34, + "gen_feat_2": 0.494893, + "gen_feat_3": 492.66 + } + }, + { + "id": "t_transit_gen_3", + "task_id": "t_transit", + "provider_id": "p_gen_1", + "name": "Google Transit API (Gen p_gen_1)", + "features": { + "latency_ms": 454.73, + "cost_usd": 0.0, + "availability": 0.982378, + "gen_feat_1": 508.31, + "gen_feat_2": 0.486183, + "gen_feat_3": 501.39 + } + }, + { + "id": "t_transit_gen_4", + "task_id": "t_transit", + "provider_id": "p_gen_2", + "name": "Google Transit API (Gen p_gen_2)", + "features": { + "latency_ms": 463.1, + "cost_usd": 0.0, + "availability": 0.967212, + "gen_feat_1": 512.89, + "gen_feat_2": 0.512956, + "gen_feat_3": 495.23 + } + }, + { + "id": "t_transit_gen_5", + "task_id": "t_transit", + "provider_id": "p_gen_3", + "name": "Google Transit API (Gen p_gen_3)", + "features": { + "latency_ms": 456.23, + "cost_usd": 0.0, + "availability": 0.965992, + "gen_feat_1": 490.49, + "gen_feat_2": 0.508133, + "gen_feat_3": 504.92 + } + }, + { + "id": "t_transit_gen_6", + "task_id": "t_transit", + "provider_id": "p_gen_4", + "name": "Google Transit API (Gen p_gen_4)", + "features": { + "latency_ms": 440.18, + "cost_usd": 0.0, + "availability": 0.991733, + "gen_feat_1": 490.83, + "gen_feat_2": 0.504993, + "gen_feat_3": 492.89 + } + }, + { + "id": "t_transit_gen_7", + "task_id": "t_transit", + "provider_id": "p_gen_5", + "name": "Google Transit API (Gen p_gen_5)", + "features": { + "latency_ms": 462.92, + "cost_usd": 0.0, + "availability": 0.996902, + "gen_feat_1": 511.69, + "gen_feat_2": 0.506072, + "gen_feat_3": 487.84 + } + }, + { + "id": "t_transit_gen_8", + "task_id": "t_transit", + "provider_id": "p_google", + "name": "Google Transit API (Gen p_google)", + "features": { + "latency_ms": 437.2, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 486.88, + "gen_feat_2": 0.486007, + "gen_feat_3": 512.05 + } + }, + { + "id": "t_transit_gen_9", + "task_id": "t_transit", + "provider_id": "p_amazon", + "name": "Google Transit API (Gen p_amazon)", + "features": { + "latency_ms": 454.11, + "cost_usd": 0.0, + "availability": 0.993251, + "gen_feat_1": 496.88, + "gen_feat_2": 0.494363, + "gen_feat_3": 508.7 + } + }, + { + "id": "t_archive_gen_2", + "task_id": "t_archive", + "provider_id": "p_unimib", + "name": "Archive.org API (Gen p_unimib)", + "features": { + "latency_ms": 491.38, + "cost_usd": 0.0, + "availability": 0.97419, + "gen_feat_1": 488.94, + "gen_feat_2": 0.490436, + "gen_feat_3": 502.27 + } + }, + { + "id": "t_archive_gen_3", + "task_id": "t_archive", + "provider_id": "p_archive", + "name": "Archive.org API (Gen p_archive)", + "features": { + "latency_ms": 493.0, + "cost_usd": 0.0, + "availability": 0.974135, + "gen_feat_1": 509.85, + "gen_feat_2": 0.501448, + "gen_feat_3": 508.14 + } + }, + { + "id": "t_archive_gen_4", + "task_id": "t_archive", + "provider_id": "p_local", + "name": "Archive.org API (Gen p_local)", + "features": { + "latency_ms": 506.7, + "cost_usd": 0.0, + "availability": 0.950007, + "gen_feat_1": 485.3, + "gen_feat_2": 0.506074, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_archive_gen_5", + "task_id": "t_archive", + "provider_id": "p_gen_1", + "name": "Archive.org API (Gen p_gen_1)", + "features": { + "latency_ms": 489.16, + "cost_usd": 0.0, + "availability": 0.997048, + "gen_feat_1": 498.8, + "gen_feat_2": 0.513697, + "gen_feat_3": 499.99 + } + }, + { + "id": "t_archive_gen_6", + "task_id": "t_archive", + "provider_id": "p_gen_2", + "name": "Archive.org API (Gen p_gen_2)", + "features": { + "latency_ms": 490.4, + "cost_usd": 0.0, + "availability": 0.989264, + "gen_feat_1": 499.32, + "gen_feat_2": 0.492021, + "gen_feat_3": 511.64 + } + }, + { + "id": "t_archive_gen_7", + "task_id": "t_archive", + "provider_id": "p_gen_3", + "name": "Archive.org API (Gen p_gen_3)", + "features": { + "latency_ms": 493.82, + "cost_usd": 0.0, + "availability": 0.963902, + "gen_feat_1": 513.54, + "gen_feat_2": 0.514704, + "gen_feat_3": 488.6 + } + }, + { + "id": "t_archive_gen_8", + "task_id": "t_archive", + "provider_id": "p_gen_4", + "name": "Archive.org API (Gen p_gen_4)", + "features": { + "latency_ms": 501.92, + "cost_usd": 0.0, + "availability": 0.987176, + "gen_feat_1": 487.31, + "gen_feat_2": 0.5052, + "gen_feat_3": 512.55 + } + }, + { + "id": "t_archive_gen_9", + "task_id": "t_archive", + "provider_id": "p_gen_5", + "name": "Archive.org API (Gen p_gen_5)", + "features": { + "latency_ms": 497.11, + "cost_usd": 0.0, + "availability": 0.959066, + "gen_feat_1": 489.18, + "gen_feat_2": 0.487091, + "gen_feat_3": 488.33 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_books", + "kind": "TASK", + "task_id": "t_books" + }, + { + "id": "n_parallel_options", + "kind": "AND", + "children": [ + { + "id": "n_amazon", + "kind": "TASK", + "task_id": "t_market" + }, + { + "id": "n_library_trip", + "kind": "SEQ", + "children": [ + { + "id": "n_opac", + "kind": "TASK", + "task_id": "t_library" + }, + { + "id": "n_geocode", + "kind": "TASK", + "task_id": "t_geocoding" + }, + { + "id": "n_transit", + "kind": "TASK", + "task_id": "t_transit" + } + ] + }, + { + "id": "n_archive", + "kind": "TASK", + "task_id": "t_archive" + } + ] + }, + { + "id": "n_report", + "kind": "ELEMENT", + "description": "Assemble final textbook access report" + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "objective": { + "type": "MULTI", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1" + ], + "weights": { + "availability": 0.34, + "cost_usd": 0.33, + "gen_feat_1": 0.33 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1357.94, + "hard": false + }, + { + "id": "gen_c_local_t_archive_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_archive" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_books", + "t_geocoding" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_archive", + "t_books" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/netedu2020-transport-agency_many_hard.json b/experimentation/instances/netedu2020-transport-agency_many_hard.json new file mode 100644 index 0000000..6868c3a --- /dev/null +++ b/experimentation/instances/netedu2020-transport-agency_many_hard.json @@ -0,0 +1,977 @@ +{ + "metadata": { + "id": "netedu2020-transport-agency_many_hard", + "name": "Transport Agency case study (Netedu et al. 2020) [many, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Models the running example from 'A Web Service Composition Method Based on OpenAPI Semantic Annotations' (Netedu et al., 2020), Sect. 5 Case Study: A Transport Agency. QoS values are not provided in the paper; a minimal 'cost' feature is added for schema compliance.", + "paper": { + "title": "A Web Service Composition Method Based on OpenAPI Semantic Annotations", + "authors": "A. Netedu et al.", + "year": 2020, + "doi": "10.1007/978-3-030-34986-8_25" + } + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "USD", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_transport_agency", + "name": "Transport Agency REST API" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_get_country_from_location", + "name": "getCountryFromLocation" + }, + { + "id": "t_get_transport_company", + "name": "getTransportCompany" + }, + { + "id": "t_get_closest_city", + "name": "getClosestCity" + }, + { + "id": "t_get_local_subsidiary", + "name": "getLocalSubsidiary" + }, + { + "id": "t_get_vehicle", + "name": "getVehicle" + }, + { + "id": "t_make_arrangements", + "name": "makeArrangements" + } + ], + "candidates": [ + { + "id": "c_get_country_from_location", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_transport_company", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_closest_city", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_local_subsidiary", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_vehicle", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_make_arrangements", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_get_country_from_location_gen_1", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_shared", + "name": "getCountryFromLocation (Gen Shared)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.04, + "gen_feat_2": 0.513114, + "gen_feat_3": 485.63 + } + }, + { + "id": "t_get_transport_company_gen_1", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_shared", + "name": "getTransportCompany (Gen Shared)", + "features": { + "cost": 0.99, + "gen_feat_1": 506.99, + "gen_feat_2": 0.503453, + "gen_feat_3": 502.41 + } + }, + { + "id": "t_get_closest_city_gen_1", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_shared", + "name": "getClosestCity (Gen Shared)", + "features": { + "cost": 1.02, + "gen_feat_1": 497.52, + "gen_feat_2": 0.503882, + "gen_feat_3": 496.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_1", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_shared", + "name": "getLocalSubsidiary (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 512.34, + "gen_feat_2": 0.489132, + "gen_feat_3": 506.11 + } + }, + { + "id": "t_get_vehicle_gen_1", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_shared", + "name": "getVehicle (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 502.66, + "gen_feat_2": 0.509316, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_make_arrangements_gen_1", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_shared", + "name": "makeArrangements (Gen Shared)", + "features": { + "cost": 1.03, + "gen_feat_1": 489.65, + "gen_feat_2": 0.485293, + "gen_feat_3": 513.91 + } + }, + { + "id": "t_get_country_from_location_gen_2", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 0.98, + "gen_feat_1": 487.4, + "gen_feat_2": 0.511921, + "gen_feat_3": 508.92 + } + }, + { + "id": "t_get_country_from_location_gen_3", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500027, + "gen_feat_3": 507.17 + } + }, + { + "id": "t_get_country_from_location_gen_4", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_2", + "name": "getCountryFromLocation (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 504.84, + "gen_feat_2": 0.508391, + "gen_feat_3": 492.85 + } + }, + { + "id": "t_get_country_from_location_gen_5", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_3", + "name": "getCountryFromLocation (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.58, + "gen_feat_2": 0.512949, + "gen_feat_3": 506.57 + } + }, + { + "id": "t_get_country_from_location_gen_6", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_4", + "name": "getCountryFromLocation (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 501.88, + "gen_feat_2": 0.494867, + "gen_feat_3": 507.59 + } + }, + { + "id": "t_get_country_from_location_gen_7", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_5", + "name": "getCountryFromLocation (Gen p_gen_5)", + "features": { + "cost": 0.99, + "gen_feat_1": 507.26, + "gen_feat_2": 0.491882, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_get_country_from_location_gen_8", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 506.26, + "gen_feat_2": 0.510131, + "gen_feat_3": 505.7 + } + }, + { + "id": "t_get_country_from_location_gen_9", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 486.8, + "gen_feat_2": 0.510302, + "gen_feat_3": 507.54 + } + }, + { + "id": "t_get_transport_company_gen_2", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 505.78, + "gen_feat_2": 0.498526, + "gen_feat_3": 487.5 + } + }, + { + "id": "t_get_transport_company_gen_3", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 510.84, + "gen_feat_2": 0.506966, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_get_transport_company_gen_4", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_4", + "name": "getTransportCompany (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 503.48, + "gen_feat_2": 0.500194, + "gen_feat_3": 504.85 + } + }, + { + "id": "t_get_transport_company_gen_5", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_5", + "name": "getTransportCompany (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 493.49, + "gen_feat_2": 0.491039, + "gen_feat_3": 486.86 + } + }, + { + "id": "t_get_transport_company_gen_6", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 499.16, + "gen_feat_2": 0.495989, + "gen_feat_3": 512.41 + } + }, + { + "id": "t_get_transport_company_gen_7", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_1", + "name": "getTransportCompany (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 502.63, + "gen_feat_2": 0.506883, + "gen_feat_3": 507.66 + } + }, + { + "id": "t_get_transport_company_gen_8", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 491.72, + "gen_feat_2": 0.493913, + "gen_feat_3": 499.04 + } + }, + { + "id": "t_get_transport_company_gen_9", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 511.11, + "gen_feat_2": 0.49489, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_get_closest_city_gen_2", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 0.98, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514837, + "gen_feat_3": 502.45 + } + }, + { + "id": "t_get_closest_city_gen_3", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.16, + "gen_feat_2": 0.510642, + "gen_feat_3": 497.88 + } + }, + { + "id": "t_get_closest_city_gen_4", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 493.82, + "gen_feat_2": 0.509042, + "gen_feat_3": 492.58 + } + }, + { + "id": "t_get_closest_city_gen_5", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_1", + "name": "getClosestCity (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 485.83, + "gen_feat_2": 0.508367, + "gen_feat_3": 502.67 + } + }, + { + "id": "t_get_closest_city_gen_6", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_2", + "name": "getClosestCity (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 510.35, + "gen_feat_2": 0.507866, + "gen_feat_3": 485.56 + } + }, + { + "id": "t_get_closest_city_gen_7", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_3", + "name": "getClosestCity (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 506.43, + "gen_feat_2": 0.485825, + "gen_feat_3": 496.36 + } + }, + { + "id": "t_get_closest_city_gen_8", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 511.75, + "gen_feat_2": 0.497873, + "gen_feat_3": 487.86 + } + }, + { + "id": "t_get_closest_city_gen_9", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 489.25, + "gen_feat_2": 0.493981, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_2", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 513.51, + "gen_feat_2": 0.496631, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_get_local_subsidiary_gen_3", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 493.1, + "gen_feat_2": 0.495292, + "gen_feat_3": 510.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_4", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_2", + "name": "getLocalSubsidiary (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 490.37, + "gen_feat_2": 0.513325, + "gen_feat_3": 498.92 + } + }, + { + "id": "t_get_local_subsidiary_gen_5", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_3", + "name": "getLocalSubsidiary (Gen p_gen_3)", + "features": { + "cost": 1.0, + "gen_feat_1": 502.56, + "gen_feat_2": 0.499451, + "gen_feat_3": 508.64 + } + }, + { + "id": "t_get_local_subsidiary_gen_6", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_4", + "name": "getLocalSubsidiary (Gen p_gen_4)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.52, + "gen_feat_2": 0.505343, + "gen_feat_3": 497.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_7", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_5", + "name": "getLocalSubsidiary (Gen p_gen_5)", + "features": { + "cost": 0.97, + "gen_feat_1": 508.83, + "gen_feat_2": 0.505122, + "gen_feat_3": 493.09 + } + }, + { + "id": "t_get_local_subsidiary_gen_8", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.02, + "gen_feat_1": 498.4, + "gen_feat_2": 0.51387, + "gen_feat_3": 507.57 + } + }, + { + "id": "t_get_local_subsidiary_gen_9", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.29, + "gen_feat_2": 0.501427, + "gen_feat_3": 499.52 + } + }, + { + "id": "t_get_vehicle_gen_2", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 489.79, + "gen_feat_2": 0.496462, + "gen_feat_3": 494.94 + } + }, + { + "id": "t_get_vehicle_gen_3", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 0.99, + "gen_feat_1": 487.88, + "gen_feat_2": 0.493816, + "gen_feat_3": 501.37 + } + }, + { + "id": "t_get_vehicle_gen_4", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_4", + "name": "getVehicle (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 498.07, + "gen_feat_2": 0.509826, + "gen_feat_3": 513.13 + } + }, + { + "id": "t_get_vehicle_gen_5", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_5", + "name": "getVehicle (Gen p_gen_5)", + "features": { + "cost": 1.03, + "gen_feat_1": 503.58, + "gen_feat_2": 0.508911, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_get_vehicle_gen_6", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle (Gen p_transport_agency)", + "features": { + "cost": 0.99, + "gen_feat_1": 510.19, + "gen_feat_2": 0.504186, + "gen_feat_3": 511.03 + } + }, + { + "id": "t_get_vehicle_gen_7", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_1", + "name": "getVehicle (Gen p_gen_1)", + "features": { + "cost": 1.0, + "gen_feat_1": 503.59, + "gen_feat_2": 0.488626, + "gen_feat_3": 505.75 + } + }, + { + "id": "t_get_vehicle_gen_8", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 503.39, + "gen_feat_2": 0.487699, + "gen_feat_3": 511.79 + } + }, + { + "id": "t_get_vehicle_gen_9", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 512.8, + "gen_feat_2": 0.503185, + "gen_feat_3": 496.01 + } + }, + { + "id": "t_make_arrangements_gen_2", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 492.14, + "gen_feat_2": 0.488787, + "gen_feat_3": 502.39 + } + }, + { + "id": "t_make_arrangements_gen_3", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 494.15, + "gen_feat_2": 0.501903, + "gen_feat_3": 504.55 + } + }, + { + "id": "t_make_arrangements_gen_4", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.81, + "gen_feat_2": 0.488585, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_make_arrangements_gen_5", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_1", + "name": "makeArrangements (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.66, + "gen_feat_2": 0.486683, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_make_arrangements_gen_6", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_2", + "name": "makeArrangements (Gen p_gen_2)", + "features": { + "cost": 1.0, + "gen_feat_1": 513.24, + "gen_feat_2": 0.493676, + "gen_feat_3": 494.85 + } + }, + { + "id": "t_make_arrangements_gen_7", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_3", + "name": "makeArrangements (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513493, + "gen_feat_3": 496.34 + } + }, + { + "id": "t_make_arrangements_gen_8", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 0.99, + "gen_feat_1": 513.6, + "gen_feat_2": 0.503479, + "gen_feat_3": 494.88 + } + }, + { + "id": "t_make_arrangements_gen_9", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 510.22, + "gen_feat_2": 0.498065, + "gen_feat_3": 500.63 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_country", + "kind": "TASK", + "task_id": "t_get_country_from_location" + }, + { + "id": "n_company", + "kind": "TASK", + "task_id": "t_get_transport_company" + }, + { + "id": "n_city", + "kind": "TASK", + "task_id": "t_get_closest_city" + }, + { + "id": "n_subsidiary", + "kind": "TASK", + "task_id": "t_get_local_subsidiary" + }, + { + "id": "n_vehicle", + "kind": "TASK", + "task_id": "t_get_vehicle" + }, + { + "id": "n_arrangements", + "kind": "TASK", + "task_id": "t_make_arrangements" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + } + }, + "objective": { + "type": "MANY", + "targets": [ + "cost", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3" + ], + "weights": { + "cost": 0.25, + "gen_feat_1": 0.25, + "gen_feat_2": 0.25, + "gen_feat_3": 0.25 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 6.01, + "hard": true + }, + { + "id": "gen_c_local_t_get_closest_city_gen_feat_1_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_get_closest_city" + ], + "attribute_id": "gen_feat_1", + "op": "<=", + "value": 497.52, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_get_country_from_location" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_make_arrangements" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/netedu2020-transport-agency_many_soft.json b/experimentation/instances/netedu2020-transport-agency_many_soft.json new file mode 100644 index 0000000..96e3eef --- /dev/null +++ b/experimentation/instances/netedu2020-transport-agency_many_soft.json @@ -0,0 +1,977 @@ +{ + "metadata": { + "id": "netedu2020-transport-agency_many_soft", + "name": "Transport Agency case study (Netedu et al. 2020) [many, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Models the running example from 'A Web Service Composition Method Based on OpenAPI Semantic Annotations' (Netedu et al., 2020), Sect. 5 Case Study: A Transport Agency. QoS values are not provided in the paper; a minimal 'cost' feature is added for schema compliance.", + "paper": { + "title": "A Web Service Composition Method Based on OpenAPI Semantic Annotations", + "authors": "A. Netedu et al.", + "year": 2020, + "doi": "10.1007/978-3-030-34986-8_25" + } + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "USD", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_transport_agency", + "name": "Transport Agency REST API" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_get_country_from_location", + "name": "getCountryFromLocation" + }, + { + "id": "t_get_transport_company", + "name": "getTransportCompany" + }, + { + "id": "t_get_closest_city", + "name": "getClosestCity" + }, + { + "id": "t_get_local_subsidiary", + "name": "getLocalSubsidiary" + }, + { + "id": "t_get_vehicle", + "name": "getVehicle" + }, + { + "id": "t_make_arrangements", + "name": "makeArrangements" + } + ], + "candidates": [ + { + "id": "c_get_country_from_location", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_transport_company", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_closest_city", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_local_subsidiary", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_vehicle", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_make_arrangements", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_get_country_from_location_gen_1", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_shared", + "name": "getCountryFromLocation (Gen Shared)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.04, + "gen_feat_2": 0.513114, + "gen_feat_3": 485.63 + } + }, + { + "id": "t_get_transport_company_gen_1", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_shared", + "name": "getTransportCompany (Gen Shared)", + "features": { + "cost": 0.99, + "gen_feat_1": 506.99, + "gen_feat_2": 0.503453, + "gen_feat_3": 502.41 + } + }, + { + "id": "t_get_closest_city_gen_1", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_shared", + "name": "getClosestCity (Gen Shared)", + "features": { + "cost": 1.02, + "gen_feat_1": 497.52, + "gen_feat_2": 0.503882, + "gen_feat_3": 496.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_1", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_shared", + "name": "getLocalSubsidiary (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 512.34, + "gen_feat_2": 0.489132, + "gen_feat_3": 506.11 + } + }, + { + "id": "t_get_vehicle_gen_1", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_shared", + "name": "getVehicle (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 502.66, + "gen_feat_2": 0.509316, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_make_arrangements_gen_1", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_shared", + "name": "makeArrangements (Gen Shared)", + "features": { + "cost": 1.03, + "gen_feat_1": 489.65, + "gen_feat_2": 0.485293, + "gen_feat_3": 513.91 + } + }, + { + "id": "t_get_country_from_location_gen_2", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 0.98, + "gen_feat_1": 487.4, + "gen_feat_2": 0.511921, + "gen_feat_3": 508.92 + } + }, + { + "id": "t_get_country_from_location_gen_3", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500027, + "gen_feat_3": 507.17 + } + }, + { + "id": "t_get_country_from_location_gen_4", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_2", + "name": "getCountryFromLocation (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 504.84, + "gen_feat_2": 0.508391, + "gen_feat_3": 492.85 + } + }, + { + "id": "t_get_country_from_location_gen_5", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_3", + "name": "getCountryFromLocation (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.58, + "gen_feat_2": 0.512949, + "gen_feat_3": 506.57 + } + }, + { + "id": "t_get_country_from_location_gen_6", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_4", + "name": "getCountryFromLocation (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 501.88, + "gen_feat_2": 0.494867, + "gen_feat_3": 507.59 + } + }, + { + "id": "t_get_country_from_location_gen_7", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_5", + "name": "getCountryFromLocation (Gen p_gen_5)", + "features": { + "cost": 0.99, + "gen_feat_1": 507.26, + "gen_feat_2": 0.491882, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_get_country_from_location_gen_8", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 506.26, + "gen_feat_2": 0.510131, + "gen_feat_3": 505.7 + } + }, + { + "id": "t_get_country_from_location_gen_9", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 486.8, + "gen_feat_2": 0.510302, + "gen_feat_3": 507.54 + } + }, + { + "id": "t_get_transport_company_gen_2", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 505.78, + "gen_feat_2": 0.498526, + "gen_feat_3": 487.5 + } + }, + { + "id": "t_get_transport_company_gen_3", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 510.84, + "gen_feat_2": 0.506966, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_get_transport_company_gen_4", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_4", + "name": "getTransportCompany (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 503.48, + "gen_feat_2": 0.500194, + "gen_feat_3": 504.85 + } + }, + { + "id": "t_get_transport_company_gen_5", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_5", + "name": "getTransportCompany (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 493.49, + "gen_feat_2": 0.491039, + "gen_feat_3": 486.86 + } + }, + { + "id": "t_get_transport_company_gen_6", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 499.16, + "gen_feat_2": 0.495989, + "gen_feat_3": 512.41 + } + }, + { + "id": "t_get_transport_company_gen_7", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_1", + "name": "getTransportCompany (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 502.63, + "gen_feat_2": 0.506883, + "gen_feat_3": 507.66 + } + }, + { + "id": "t_get_transport_company_gen_8", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 491.72, + "gen_feat_2": 0.493913, + "gen_feat_3": 499.04 + } + }, + { + "id": "t_get_transport_company_gen_9", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 511.11, + "gen_feat_2": 0.49489, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_get_closest_city_gen_2", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 0.98, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514837, + "gen_feat_3": 502.45 + } + }, + { + "id": "t_get_closest_city_gen_3", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.16, + "gen_feat_2": 0.510642, + "gen_feat_3": 497.88 + } + }, + { + "id": "t_get_closest_city_gen_4", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 493.82, + "gen_feat_2": 0.509042, + "gen_feat_3": 492.58 + } + }, + { + "id": "t_get_closest_city_gen_5", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_1", + "name": "getClosestCity (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 485.83, + "gen_feat_2": 0.508367, + "gen_feat_3": 502.67 + } + }, + { + "id": "t_get_closest_city_gen_6", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_2", + "name": "getClosestCity (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 510.35, + "gen_feat_2": 0.507866, + "gen_feat_3": 485.56 + } + }, + { + "id": "t_get_closest_city_gen_7", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_3", + "name": "getClosestCity (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 506.43, + "gen_feat_2": 0.485825, + "gen_feat_3": 496.36 + } + }, + { + "id": "t_get_closest_city_gen_8", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 511.75, + "gen_feat_2": 0.497873, + "gen_feat_3": 487.86 + } + }, + { + "id": "t_get_closest_city_gen_9", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 489.25, + "gen_feat_2": 0.493981, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_2", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 513.51, + "gen_feat_2": 0.496631, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_get_local_subsidiary_gen_3", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 493.1, + "gen_feat_2": 0.495292, + "gen_feat_3": 510.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_4", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_2", + "name": "getLocalSubsidiary (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 490.37, + "gen_feat_2": 0.513325, + "gen_feat_3": 498.92 + } + }, + { + "id": "t_get_local_subsidiary_gen_5", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_3", + "name": "getLocalSubsidiary (Gen p_gen_3)", + "features": { + "cost": 1.0, + "gen_feat_1": 502.56, + "gen_feat_2": 0.499451, + "gen_feat_3": 508.64 + } + }, + { + "id": "t_get_local_subsidiary_gen_6", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_4", + "name": "getLocalSubsidiary (Gen p_gen_4)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.52, + "gen_feat_2": 0.505343, + "gen_feat_3": 497.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_7", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_5", + "name": "getLocalSubsidiary (Gen p_gen_5)", + "features": { + "cost": 0.97, + "gen_feat_1": 508.83, + "gen_feat_2": 0.505122, + "gen_feat_3": 493.09 + } + }, + { + "id": "t_get_local_subsidiary_gen_8", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.02, + "gen_feat_1": 498.4, + "gen_feat_2": 0.51387, + "gen_feat_3": 507.57 + } + }, + { + "id": "t_get_local_subsidiary_gen_9", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.29, + "gen_feat_2": 0.501427, + "gen_feat_3": 499.52 + } + }, + { + "id": "t_get_vehicle_gen_2", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 489.79, + "gen_feat_2": 0.496462, + "gen_feat_3": 494.94 + } + }, + { + "id": "t_get_vehicle_gen_3", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 0.99, + "gen_feat_1": 487.88, + "gen_feat_2": 0.493816, + "gen_feat_3": 501.37 + } + }, + { + "id": "t_get_vehicle_gen_4", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_4", + "name": "getVehicle (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 498.07, + "gen_feat_2": 0.509826, + "gen_feat_3": 513.13 + } + }, + { + "id": "t_get_vehicle_gen_5", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_5", + "name": "getVehicle (Gen p_gen_5)", + "features": { + "cost": 1.03, + "gen_feat_1": 503.58, + "gen_feat_2": 0.508911, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_get_vehicle_gen_6", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle (Gen p_transport_agency)", + "features": { + "cost": 0.99, + "gen_feat_1": 510.19, + "gen_feat_2": 0.504186, + "gen_feat_3": 511.03 + } + }, + { + "id": "t_get_vehicle_gen_7", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_1", + "name": "getVehicle (Gen p_gen_1)", + "features": { + "cost": 1.0, + "gen_feat_1": 503.59, + "gen_feat_2": 0.488626, + "gen_feat_3": 505.75 + } + }, + { + "id": "t_get_vehicle_gen_8", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 503.39, + "gen_feat_2": 0.487699, + "gen_feat_3": 511.79 + } + }, + { + "id": "t_get_vehicle_gen_9", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 512.8, + "gen_feat_2": 0.503185, + "gen_feat_3": 496.01 + } + }, + { + "id": "t_make_arrangements_gen_2", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 492.14, + "gen_feat_2": 0.488787, + "gen_feat_3": 502.39 + } + }, + { + "id": "t_make_arrangements_gen_3", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 494.15, + "gen_feat_2": 0.501903, + "gen_feat_3": 504.55 + } + }, + { + "id": "t_make_arrangements_gen_4", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.81, + "gen_feat_2": 0.488585, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_make_arrangements_gen_5", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_1", + "name": "makeArrangements (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.66, + "gen_feat_2": 0.486683, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_make_arrangements_gen_6", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_2", + "name": "makeArrangements (Gen p_gen_2)", + "features": { + "cost": 1.0, + "gen_feat_1": 513.24, + "gen_feat_2": 0.493676, + "gen_feat_3": 494.85 + } + }, + { + "id": "t_make_arrangements_gen_7", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_3", + "name": "makeArrangements (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513493, + "gen_feat_3": 496.34 + } + }, + { + "id": "t_make_arrangements_gen_8", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 0.99, + "gen_feat_1": 513.6, + "gen_feat_2": 0.503479, + "gen_feat_3": 494.88 + } + }, + { + "id": "t_make_arrangements_gen_9", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 510.22, + "gen_feat_2": 0.498065, + "gen_feat_3": 500.63 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_country", + "kind": "TASK", + "task_id": "t_get_country_from_location" + }, + { + "id": "n_company", + "kind": "TASK", + "task_id": "t_get_transport_company" + }, + { + "id": "n_city", + "kind": "TASK", + "task_id": "t_get_closest_city" + }, + { + "id": "n_subsidiary", + "kind": "TASK", + "task_id": "t_get_local_subsidiary" + }, + { + "id": "n_vehicle", + "kind": "TASK", + "task_id": "t_get_vehicle" + }, + { + "id": "n_arrangements", + "kind": "TASK", + "task_id": "t_make_arrangements" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + } + }, + "objective": { + "type": "MANY", + "targets": [ + "cost", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3" + ], + "weights": { + "cost": 0.25, + "gen_feat_1": 0.25, + "gen_feat_2": 0.25, + "gen_feat_3": 0.25 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 6.01, + "hard": false + }, + { + "id": "gen_c_local_t_get_closest_city_gen_feat_1_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_get_closest_city" + ], + "attribute_id": "gen_feat_1", + "op": "<=", + "value": 497.52, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_get_country_from_location" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_make_arrangements" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/netedu2020-transport-agency_mono_one_hard.json b/experimentation/instances/netedu2020-transport-agency_mono_one_hard.json new file mode 100644 index 0000000..47c6a0a --- /dev/null +++ b/experimentation/instances/netedu2020-transport-agency_mono_one_hard.json @@ -0,0 +1,971 @@ +{ + "metadata": { + "id": "netedu2020-transport-agency_mono_one_hard", + "name": "Transport Agency case study (Netedu et al. 2020) [mono_one, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Models the running example from 'A Web Service Composition Method Based on OpenAPI Semantic Annotations' (Netedu et al., 2020), Sect. 5 Case Study: A Transport Agency. QoS values are not provided in the paper; a minimal 'cost' feature is added for schema compliance.", + "paper": { + "title": "A Web Service Composition Method Based on OpenAPI Semantic Annotations", + "authors": "A. Netedu et al.", + "year": 2020, + "doi": "10.1007/978-3-030-34986-8_25" + } + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "USD", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_transport_agency", + "name": "Transport Agency REST API" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_get_country_from_location", + "name": "getCountryFromLocation" + }, + { + "id": "t_get_transport_company", + "name": "getTransportCompany" + }, + { + "id": "t_get_closest_city", + "name": "getClosestCity" + }, + { + "id": "t_get_local_subsidiary", + "name": "getLocalSubsidiary" + }, + { + "id": "t_get_vehicle", + "name": "getVehicle" + }, + { + "id": "t_make_arrangements", + "name": "makeArrangements" + } + ], + "candidates": [ + { + "id": "c_get_country_from_location", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_transport_company", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_closest_city", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_local_subsidiary", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_vehicle", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_make_arrangements", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_get_country_from_location_gen_1", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_shared", + "name": "getCountryFromLocation (Gen Shared)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.04, + "gen_feat_2": 0.513114, + "gen_feat_3": 485.63 + } + }, + { + "id": "t_get_transport_company_gen_1", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_shared", + "name": "getTransportCompany (Gen Shared)", + "features": { + "cost": 0.99, + "gen_feat_1": 506.99, + "gen_feat_2": 0.503453, + "gen_feat_3": 502.41 + } + }, + { + "id": "t_get_closest_city_gen_1", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_shared", + "name": "getClosestCity (Gen Shared)", + "features": { + "cost": 1.02, + "gen_feat_1": 497.52, + "gen_feat_2": 0.503882, + "gen_feat_3": 496.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_1", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_shared", + "name": "getLocalSubsidiary (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 512.34, + "gen_feat_2": 0.489132, + "gen_feat_3": 506.11 + } + }, + { + "id": "t_get_vehicle_gen_1", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_shared", + "name": "getVehicle (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 502.66, + "gen_feat_2": 0.509316, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_make_arrangements_gen_1", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_shared", + "name": "makeArrangements (Gen Shared)", + "features": { + "cost": 1.03, + "gen_feat_1": 489.65, + "gen_feat_2": 0.485293, + "gen_feat_3": 513.91 + } + }, + { + "id": "t_get_country_from_location_gen_2", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 0.98, + "gen_feat_1": 487.4, + "gen_feat_2": 0.511921, + "gen_feat_3": 508.92 + } + }, + { + "id": "t_get_country_from_location_gen_3", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500027, + "gen_feat_3": 507.17 + } + }, + { + "id": "t_get_country_from_location_gen_4", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_2", + "name": "getCountryFromLocation (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 504.84, + "gen_feat_2": 0.508391, + "gen_feat_3": 492.85 + } + }, + { + "id": "t_get_country_from_location_gen_5", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_3", + "name": "getCountryFromLocation (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.58, + "gen_feat_2": 0.512949, + "gen_feat_3": 506.57 + } + }, + { + "id": "t_get_country_from_location_gen_6", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_4", + "name": "getCountryFromLocation (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 501.88, + "gen_feat_2": 0.494867, + "gen_feat_3": 507.59 + } + }, + { + "id": "t_get_country_from_location_gen_7", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_5", + "name": "getCountryFromLocation (Gen p_gen_5)", + "features": { + "cost": 0.99, + "gen_feat_1": 507.26, + "gen_feat_2": 0.491882, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_get_country_from_location_gen_8", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 506.26, + "gen_feat_2": 0.510131, + "gen_feat_3": 505.7 + } + }, + { + "id": "t_get_country_from_location_gen_9", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 486.8, + "gen_feat_2": 0.510302, + "gen_feat_3": 507.54 + } + }, + { + "id": "t_get_transport_company_gen_2", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 505.78, + "gen_feat_2": 0.498526, + "gen_feat_3": 487.5 + } + }, + { + "id": "t_get_transport_company_gen_3", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 510.84, + "gen_feat_2": 0.506966, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_get_transport_company_gen_4", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_4", + "name": "getTransportCompany (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 503.48, + "gen_feat_2": 0.500194, + "gen_feat_3": 504.85 + } + }, + { + "id": "t_get_transport_company_gen_5", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_5", + "name": "getTransportCompany (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 493.49, + "gen_feat_2": 0.491039, + "gen_feat_3": 486.86 + } + }, + { + "id": "t_get_transport_company_gen_6", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 499.16, + "gen_feat_2": 0.495989, + "gen_feat_3": 512.41 + } + }, + { + "id": "t_get_transport_company_gen_7", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_1", + "name": "getTransportCompany (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 502.63, + "gen_feat_2": 0.506883, + "gen_feat_3": 507.66 + } + }, + { + "id": "t_get_transport_company_gen_8", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 491.72, + "gen_feat_2": 0.493913, + "gen_feat_3": 499.04 + } + }, + { + "id": "t_get_transport_company_gen_9", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 511.11, + "gen_feat_2": 0.49489, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_get_closest_city_gen_2", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 0.98, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514837, + "gen_feat_3": 502.45 + } + }, + { + "id": "t_get_closest_city_gen_3", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.16, + "gen_feat_2": 0.510642, + "gen_feat_3": 497.88 + } + }, + { + "id": "t_get_closest_city_gen_4", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 493.82, + "gen_feat_2": 0.509042, + "gen_feat_3": 492.58 + } + }, + { + "id": "t_get_closest_city_gen_5", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_1", + "name": "getClosestCity (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 485.83, + "gen_feat_2": 0.508367, + "gen_feat_3": 502.67 + } + }, + { + "id": "t_get_closest_city_gen_6", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_2", + "name": "getClosestCity (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 510.35, + "gen_feat_2": 0.507866, + "gen_feat_3": 485.56 + } + }, + { + "id": "t_get_closest_city_gen_7", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_3", + "name": "getClosestCity (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 506.43, + "gen_feat_2": 0.485825, + "gen_feat_3": 496.36 + } + }, + { + "id": "t_get_closest_city_gen_8", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 511.75, + "gen_feat_2": 0.497873, + "gen_feat_3": 487.86 + } + }, + { + "id": "t_get_closest_city_gen_9", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 489.25, + "gen_feat_2": 0.493981, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_2", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 513.51, + "gen_feat_2": 0.496631, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_get_local_subsidiary_gen_3", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 493.1, + "gen_feat_2": 0.495292, + "gen_feat_3": 510.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_4", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_2", + "name": "getLocalSubsidiary (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 490.37, + "gen_feat_2": 0.513325, + "gen_feat_3": 498.92 + } + }, + { + "id": "t_get_local_subsidiary_gen_5", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_3", + "name": "getLocalSubsidiary (Gen p_gen_3)", + "features": { + "cost": 1.0, + "gen_feat_1": 502.56, + "gen_feat_2": 0.499451, + "gen_feat_3": 508.64 + } + }, + { + "id": "t_get_local_subsidiary_gen_6", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_4", + "name": "getLocalSubsidiary (Gen p_gen_4)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.52, + "gen_feat_2": 0.505343, + "gen_feat_3": 497.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_7", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_5", + "name": "getLocalSubsidiary (Gen p_gen_5)", + "features": { + "cost": 0.97, + "gen_feat_1": 508.83, + "gen_feat_2": 0.505122, + "gen_feat_3": 493.09 + } + }, + { + "id": "t_get_local_subsidiary_gen_8", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.02, + "gen_feat_1": 498.4, + "gen_feat_2": 0.51387, + "gen_feat_3": 507.57 + } + }, + { + "id": "t_get_local_subsidiary_gen_9", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.29, + "gen_feat_2": 0.501427, + "gen_feat_3": 499.52 + } + }, + { + "id": "t_get_vehicle_gen_2", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 489.79, + "gen_feat_2": 0.496462, + "gen_feat_3": 494.94 + } + }, + { + "id": "t_get_vehicle_gen_3", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 0.99, + "gen_feat_1": 487.88, + "gen_feat_2": 0.493816, + "gen_feat_3": 501.37 + } + }, + { + "id": "t_get_vehicle_gen_4", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_4", + "name": "getVehicle (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 498.07, + "gen_feat_2": 0.509826, + "gen_feat_3": 513.13 + } + }, + { + "id": "t_get_vehicle_gen_5", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_5", + "name": "getVehicle (Gen p_gen_5)", + "features": { + "cost": 1.03, + "gen_feat_1": 503.58, + "gen_feat_2": 0.508911, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_get_vehicle_gen_6", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle (Gen p_transport_agency)", + "features": { + "cost": 0.99, + "gen_feat_1": 510.19, + "gen_feat_2": 0.504186, + "gen_feat_3": 511.03 + } + }, + { + "id": "t_get_vehicle_gen_7", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_1", + "name": "getVehicle (Gen p_gen_1)", + "features": { + "cost": 1.0, + "gen_feat_1": 503.59, + "gen_feat_2": 0.488626, + "gen_feat_3": 505.75 + } + }, + { + "id": "t_get_vehicle_gen_8", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 503.39, + "gen_feat_2": 0.487699, + "gen_feat_3": 511.79 + } + }, + { + "id": "t_get_vehicle_gen_9", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 512.8, + "gen_feat_2": 0.503185, + "gen_feat_3": 496.01 + } + }, + { + "id": "t_make_arrangements_gen_2", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 492.14, + "gen_feat_2": 0.488787, + "gen_feat_3": 502.39 + } + }, + { + "id": "t_make_arrangements_gen_3", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 494.15, + "gen_feat_2": 0.501903, + "gen_feat_3": 504.55 + } + }, + { + "id": "t_make_arrangements_gen_4", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.81, + "gen_feat_2": 0.488585, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_make_arrangements_gen_5", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_1", + "name": "makeArrangements (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.66, + "gen_feat_2": 0.486683, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_make_arrangements_gen_6", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_2", + "name": "makeArrangements (Gen p_gen_2)", + "features": { + "cost": 1.0, + "gen_feat_1": 513.24, + "gen_feat_2": 0.493676, + "gen_feat_3": 494.85 + } + }, + { + "id": "t_make_arrangements_gen_7", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_3", + "name": "makeArrangements (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513493, + "gen_feat_3": 496.34 + } + }, + { + "id": "t_make_arrangements_gen_8", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 0.99, + "gen_feat_1": 513.6, + "gen_feat_2": 0.503479, + "gen_feat_3": 494.88 + } + }, + { + "id": "t_make_arrangements_gen_9", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 510.22, + "gen_feat_2": 0.498065, + "gen_feat_3": 500.63 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_country", + "kind": "TASK", + "task_id": "t_get_country_from_location" + }, + { + "id": "n_company", + "kind": "TASK", + "task_id": "t_get_transport_company" + }, + { + "id": "n_city", + "kind": "TASK", + "task_id": "t_get_closest_city" + }, + { + "id": "n_subsidiary", + "kind": "TASK", + "task_id": "t_get_local_subsidiary" + }, + { + "id": "n_vehicle", + "kind": "TASK", + "task_id": "t_get_vehicle" + }, + { + "id": "n_arrangements", + "kind": "TASK", + "task_id": "t_make_arrangements" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "cost" + ], + "weights": { + "cost": 1.0 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 6.01, + "hard": true + }, + { + "id": "gen_c_local_t_get_closest_city_gen_feat_1_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_get_closest_city" + ], + "attribute_id": "gen_feat_1", + "op": "<=", + "value": 497.52, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_get_country_from_location" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_make_arrangements" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/netedu2020-transport-agency_mono_one_soft.json b/experimentation/instances/netedu2020-transport-agency_mono_one_soft.json new file mode 100644 index 0000000..bb1a81a --- /dev/null +++ b/experimentation/instances/netedu2020-transport-agency_mono_one_soft.json @@ -0,0 +1,971 @@ +{ + "metadata": { + "id": "netedu2020-transport-agency_mono_one_soft", + "name": "Transport Agency case study (Netedu et al. 2020) [mono_one, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Models the running example from 'A Web Service Composition Method Based on OpenAPI Semantic Annotations' (Netedu et al., 2020), Sect. 5 Case Study: A Transport Agency. QoS values are not provided in the paper; a minimal 'cost' feature is added for schema compliance.", + "paper": { + "title": "A Web Service Composition Method Based on OpenAPI Semantic Annotations", + "authors": "A. Netedu et al.", + "year": 2020, + "doi": "10.1007/978-3-030-34986-8_25" + } + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "USD", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_transport_agency", + "name": "Transport Agency REST API" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_get_country_from_location", + "name": "getCountryFromLocation" + }, + { + "id": "t_get_transport_company", + "name": "getTransportCompany" + }, + { + "id": "t_get_closest_city", + "name": "getClosestCity" + }, + { + "id": "t_get_local_subsidiary", + "name": "getLocalSubsidiary" + }, + { + "id": "t_get_vehicle", + "name": "getVehicle" + }, + { + "id": "t_make_arrangements", + "name": "makeArrangements" + } + ], + "candidates": [ + { + "id": "c_get_country_from_location", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_transport_company", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_closest_city", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_local_subsidiary", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_vehicle", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_make_arrangements", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_get_country_from_location_gen_1", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_shared", + "name": "getCountryFromLocation (Gen Shared)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.04, + "gen_feat_2": 0.513114, + "gen_feat_3": 485.63 + } + }, + { + "id": "t_get_transport_company_gen_1", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_shared", + "name": "getTransportCompany (Gen Shared)", + "features": { + "cost": 0.99, + "gen_feat_1": 506.99, + "gen_feat_2": 0.503453, + "gen_feat_3": 502.41 + } + }, + { + "id": "t_get_closest_city_gen_1", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_shared", + "name": "getClosestCity (Gen Shared)", + "features": { + "cost": 1.02, + "gen_feat_1": 497.52, + "gen_feat_2": 0.503882, + "gen_feat_3": 496.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_1", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_shared", + "name": "getLocalSubsidiary (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 512.34, + "gen_feat_2": 0.489132, + "gen_feat_3": 506.11 + } + }, + { + "id": "t_get_vehicle_gen_1", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_shared", + "name": "getVehicle (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 502.66, + "gen_feat_2": 0.509316, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_make_arrangements_gen_1", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_shared", + "name": "makeArrangements (Gen Shared)", + "features": { + "cost": 1.03, + "gen_feat_1": 489.65, + "gen_feat_2": 0.485293, + "gen_feat_3": 513.91 + } + }, + { + "id": "t_get_country_from_location_gen_2", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 0.98, + "gen_feat_1": 487.4, + "gen_feat_2": 0.511921, + "gen_feat_3": 508.92 + } + }, + { + "id": "t_get_country_from_location_gen_3", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500027, + "gen_feat_3": 507.17 + } + }, + { + "id": "t_get_country_from_location_gen_4", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_2", + "name": "getCountryFromLocation (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 504.84, + "gen_feat_2": 0.508391, + "gen_feat_3": 492.85 + } + }, + { + "id": "t_get_country_from_location_gen_5", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_3", + "name": "getCountryFromLocation (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.58, + "gen_feat_2": 0.512949, + "gen_feat_3": 506.57 + } + }, + { + "id": "t_get_country_from_location_gen_6", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_4", + "name": "getCountryFromLocation (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 501.88, + "gen_feat_2": 0.494867, + "gen_feat_3": 507.59 + } + }, + { + "id": "t_get_country_from_location_gen_7", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_5", + "name": "getCountryFromLocation (Gen p_gen_5)", + "features": { + "cost": 0.99, + "gen_feat_1": 507.26, + "gen_feat_2": 0.491882, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_get_country_from_location_gen_8", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 506.26, + "gen_feat_2": 0.510131, + "gen_feat_3": 505.7 + } + }, + { + "id": "t_get_country_from_location_gen_9", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 486.8, + "gen_feat_2": 0.510302, + "gen_feat_3": 507.54 + } + }, + { + "id": "t_get_transport_company_gen_2", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 505.78, + "gen_feat_2": 0.498526, + "gen_feat_3": 487.5 + } + }, + { + "id": "t_get_transport_company_gen_3", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 510.84, + "gen_feat_2": 0.506966, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_get_transport_company_gen_4", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_4", + "name": "getTransportCompany (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 503.48, + "gen_feat_2": 0.500194, + "gen_feat_3": 504.85 + } + }, + { + "id": "t_get_transport_company_gen_5", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_5", + "name": "getTransportCompany (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 493.49, + "gen_feat_2": 0.491039, + "gen_feat_3": 486.86 + } + }, + { + "id": "t_get_transport_company_gen_6", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 499.16, + "gen_feat_2": 0.495989, + "gen_feat_3": 512.41 + } + }, + { + "id": "t_get_transport_company_gen_7", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_1", + "name": "getTransportCompany (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 502.63, + "gen_feat_2": 0.506883, + "gen_feat_3": 507.66 + } + }, + { + "id": "t_get_transport_company_gen_8", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 491.72, + "gen_feat_2": 0.493913, + "gen_feat_3": 499.04 + } + }, + { + "id": "t_get_transport_company_gen_9", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 511.11, + "gen_feat_2": 0.49489, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_get_closest_city_gen_2", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 0.98, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514837, + "gen_feat_3": 502.45 + } + }, + { + "id": "t_get_closest_city_gen_3", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.16, + "gen_feat_2": 0.510642, + "gen_feat_3": 497.88 + } + }, + { + "id": "t_get_closest_city_gen_4", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 493.82, + "gen_feat_2": 0.509042, + "gen_feat_3": 492.58 + } + }, + { + "id": "t_get_closest_city_gen_5", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_1", + "name": "getClosestCity (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 485.83, + "gen_feat_2": 0.508367, + "gen_feat_3": 502.67 + } + }, + { + "id": "t_get_closest_city_gen_6", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_2", + "name": "getClosestCity (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 510.35, + "gen_feat_2": 0.507866, + "gen_feat_3": 485.56 + } + }, + { + "id": "t_get_closest_city_gen_7", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_3", + "name": "getClosestCity (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 506.43, + "gen_feat_2": 0.485825, + "gen_feat_3": 496.36 + } + }, + { + "id": "t_get_closest_city_gen_8", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 511.75, + "gen_feat_2": 0.497873, + "gen_feat_3": 487.86 + } + }, + { + "id": "t_get_closest_city_gen_9", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 489.25, + "gen_feat_2": 0.493981, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_2", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 513.51, + "gen_feat_2": 0.496631, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_get_local_subsidiary_gen_3", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 493.1, + "gen_feat_2": 0.495292, + "gen_feat_3": 510.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_4", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_2", + "name": "getLocalSubsidiary (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 490.37, + "gen_feat_2": 0.513325, + "gen_feat_3": 498.92 + } + }, + { + "id": "t_get_local_subsidiary_gen_5", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_3", + "name": "getLocalSubsidiary (Gen p_gen_3)", + "features": { + "cost": 1.0, + "gen_feat_1": 502.56, + "gen_feat_2": 0.499451, + "gen_feat_3": 508.64 + } + }, + { + "id": "t_get_local_subsidiary_gen_6", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_4", + "name": "getLocalSubsidiary (Gen p_gen_4)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.52, + "gen_feat_2": 0.505343, + "gen_feat_3": 497.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_7", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_5", + "name": "getLocalSubsidiary (Gen p_gen_5)", + "features": { + "cost": 0.97, + "gen_feat_1": 508.83, + "gen_feat_2": 0.505122, + "gen_feat_3": 493.09 + } + }, + { + "id": "t_get_local_subsidiary_gen_8", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.02, + "gen_feat_1": 498.4, + "gen_feat_2": 0.51387, + "gen_feat_3": 507.57 + } + }, + { + "id": "t_get_local_subsidiary_gen_9", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.29, + "gen_feat_2": 0.501427, + "gen_feat_3": 499.52 + } + }, + { + "id": "t_get_vehicle_gen_2", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 489.79, + "gen_feat_2": 0.496462, + "gen_feat_3": 494.94 + } + }, + { + "id": "t_get_vehicle_gen_3", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 0.99, + "gen_feat_1": 487.88, + "gen_feat_2": 0.493816, + "gen_feat_3": 501.37 + } + }, + { + "id": "t_get_vehicle_gen_4", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_4", + "name": "getVehicle (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 498.07, + "gen_feat_2": 0.509826, + "gen_feat_3": 513.13 + } + }, + { + "id": "t_get_vehicle_gen_5", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_5", + "name": "getVehicle (Gen p_gen_5)", + "features": { + "cost": 1.03, + "gen_feat_1": 503.58, + "gen_feat_2": 0.508911, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_get_vehicle_gen_6", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle (Gen p_transport_agency)", + "features": { + "cost": 0.99, + "gen_feat_1": 510.19, + "gen_feat_2": 0.504186, + "gen_feat_3": 511.03 + } + }, + { + "id": "t_get_vehicle_gen_7", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_1", + "name": "getVehicle (Gen p_gen_1)", + "features": { + "cost": 1.0, + "gen_feat_1": 503.59, + "gen_feat_2": 0.488626, + "gen_feat_3": 505.75 + } + }, + { + "id": "t_get_vehicle_gen_8", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 503.39, + "gen_feat_2": 0.487699, + "gen_feat_3": 511.79 + } + }, + { + "id": "t_get_vehicle_gen_9", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 512.8, + "gen_feat_2": 0.503185, + "gen_feat_3": 496.01 + } + }, + { + "id": "t_make_arrangements_gen_2", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 492.14, + "gen_feat_2": 0.488787, + "gen_feat_3": 502.39 + } + }, + { + "id": "t_make_arrangements_gen_3", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 494.15, + "gen_feat_2": 0.501903, + "gen_feat_3": 504.55 + } + }, + { + "id": "t_make_arrangements_gen_4", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.81, + "gen_feat_2": 0.488585, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_make_arrangements_gen_5", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_1", + "name": "makeArrangements (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.66, + "gen_feat_2": 0.486683, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_make_arrangements_gen_6", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_2", + "name": "makeArrangements (Gen p_gen_2)", + "features": { + "cost": 1.0, + "gen_feat_1": 513.24, + "gen_feat_2": 0.493676, + "gen_feat_3": 494.85 + } + }, + { + "id": "t_make_arrangements_gen_7", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_3", + "name": "makeArrangements (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513493, + "gen_feat_3": 496.34 + } + }, + { + "id": "t_make_arrangements_gen_8", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 0.99, + "gen_feat_1": 513.6, + "gen_feat_2": 0.503479, + "gen_feat_3": 494.88 + } + }, + { + "id": "t_make_arrangements_gen_9", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 510.22, + "gen_feat_2": 0.498065, + "gen_feat_3": 500.63 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_country", + "kind": "TASK", + "task_id": "t_get_country_from_location" + }, + { + "id": "n_company", + "kind": "TASK", + "task_id": "t_get_transport_company" + }, + { + "id": "n_city", + "kind": "TASK", + "task_id": "t_get_closest_city" + }, + { + "id": "n_subsidiary", + "kind": "TASK", + "task_id": "t_get_local_subsidiary" + }, + { + "id": "n_vehicle", + "kind": "TASK", + "task_id": "t_get_vehicle" + }, + { + "id": "n_arrangements", + "kind": "TASK", + "task_id": "t_make_arrangements" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "cost" + ], + "weights": { + "cost": 1.0 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 6.01, + "hard": false + }, + { + "id": "gen_c_local_t_get_closest_city_gen_feat_1_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_get_closest_city" + ], + "attribute_id": "gen_feat_1", + "op": "<=", + "value": 497.52, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_get_country_from_location" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_make_arrangements" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/netedu2020-transport-agency_mono_utility_hard.json b/experimentation/instances/netedu2020-transport-agency_mono_utility_hard.json new file mode 100644 index 0000000..587cc51 --- /dev/null +++ b/experimentation/instances/netedu2020-transport-agency_mono_utility_hard.json @@ -0,0 +1,977 @@ +{ + "metadata": { + "id": "netedu2020-transport-agency_mono_utility_hard", + "name": "Transport Agency case study (Netedu et al. 2020) [mono_utility, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Models the running example from 'A Web Service Composition Method Based on OpenAPI Semantic Annotations' (Netedu et al., 2020), Sect. 5 Case Study: A Transport Agency. QoS values are not provided in the paper; a minimal 'cost' feature is added for schema compliance.", + "paper": { + "title": "A Web Service Composition Method Based on OpenAPI Semantic Annotations", + "authors": "A. Netedu et al.", + "year": 2020, + "doi": "10.1007/978-3-030-34986-8_25" + } + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "USD", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_transport_agency", + "name": "Transport Agency REST API" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_get_country_from_location", + "name": "getCountryFromLocation" + }, + { + "id": "t_get_transport_company", + "name": "getTransportCompany" + }, + { + "id": "t_get_closest_city", + "name": "getClosestCity" + }, + { + "id": "t_get_local_subsidiary", + "name": "getLocalSubsidiary" + }, + { + "id": "t_get_vehicle", + "name": "getVehicle" + }, + { + "id": "t_make_arrangements", + "name": "makeArrangements" + } + ], + "candidates": [ + { + "id": "c_get_country_from_location", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_transport_company", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_closest_city", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_local_subsidiary", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_vehicle", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_make_arrangements", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_get_country_from_location_gen_1", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_shared", + "name": "getCountryFromLocation (Gen Shared)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.04, + "gen_feat_2": 0.513114, + "gen_feat_3": 485.63 + } + }, + { + "id": "t_get_transport_company_gen_1", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_shared", + "name": "getTransportCompany (Gen Shared)", + "features": { + "cost": 0.99, + "gen_feat_1": 506.99, + "gen_feat_2": 0.503453, + "gen_feat_3": 502.41 + } + }, + { + "id": "t_get_closest_city_gen_1", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_shared", + "name": "getClosestCity (Gen Shared)", + "features": { + "cost": 1.02, + "gen_feat_1": 497.52, + "gen_feat_2": 0.503882, + "gen_feat_3": 496.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_1", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_shared", + "name": "getLocalSubsidiary (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 512.34, + "gen_feat_2": 0.489132, + "gen_feat_3": 506.11 + } + }, + { + "id": "t_get_vehicle_gen_1", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_shared", + "name": "getVehicle (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 502.66, + "gen_feat_2": 0.509316, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_make_arrangements_gen_1", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_shared", + "name": "makeArrangements (Gen Shared)", + "features": { + "cost": 1.03, + "gen_feat_1": 489.65, + "gen_feat_2": 0.485293, + "gen_feat_3": 513.91 + } + }, + { + "id": "t_get_country_from_location_gen_2", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 0.98, + "gen_feat_1": 487.4, + "gen_feat_2": 0.511921, + "gen_feat_3": 508.92 + } + }, + { + "id": "t_get_country_from_location_gen_3", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500027, + "gen_feat_3": 507.17 + } + }, + { + "id": "t_get_country_from_location_gen_4", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_2", + "name": "getCountryFromLocation (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 504.84, + "gen_feat_2": 0.508391, + "gen_feat_3": 492.85 + } + }, + { + "id": "t_get_country_from_location_gen_5", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_3", + "name": "getCountryFromLocation (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.58, + "gen_feat_2": 0.512949, + "gen_feat_3": 506.57 + } + }, + { + "id": "t_get_country_from_location_gen_6", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_4", + "name": "getCountryFromLocation (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 501.88, + "gen_feat_2": 0.494867, + "gen_feat_3": 507.59 + } + }, + { + "id": "t_get_country_from_location_gen_7", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_5", + "name": "getCountryFromLocation (Gen p_gen_5)", + "features": { + "cost": 0.99, + "gen_feat_1": 507.26, + "gen_feat_2": 0.491882, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_get_country_from_location_gen_8", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 506.26, + "gen_feat_2": 0.510131, + "gen_feat_3": 505.7 + } + }, + { + "id": "t_get_country_from_location_gen_9", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 486.8, + "gen_feat_2": 0.510302, + "gen_feat_3": 507.54 + } + }, + { + "id": "t_get_transport_company_gen_2", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 505.78, + "gen_feat_2": 0.498526, + "gen_feat_3": 487.5 + } + }, + { + "id": "t_get_transport_company_gen_3", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 510.84, + "gen_feat_2": 0.506966, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_get_transport_company_gen_4", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_4", + "name": "getTransportCompany (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 503.48, + "gen_feat_2": 0.500194, + "gen_feat_3": 504.85 + } + }, + { + "id": "t_get_transport_company_gen_5", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_5", + "name": "getTransportCompany (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 493.49, + "gen_feat_2": 0.491039, + "gen_feat_3": 486.86 + } + }, + { + "id": "t_get_transport_company_gen_6", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 499.16, + "gen_feat_2": 0.495989, + "gen_feat_3": 512.41 + } + }, + { + "id": "t_get_transport_company_gen_7", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_1", + "name": "getTransportCompany (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 502.63, + "gen_feat_2": 0.506883, + "gen_feat_3": 507.66 + } + }, + { + "id": "t_get_transport_company_gen_8", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 491.72, + "gen_feat_2": 0.493913, + "gen_feat_3": 499.04 + } + }, + { + "id": "t_get_transport_company_gen_9", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 511.11, + "gen_feat_2": 0.49489, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_get_closest_city_gen_2", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 0.98, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514837, + "gen_feat_3": 502.45 + } + }, + { + "id": "t_get_closest_city_gen_3", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.16, + "gen_feat_2": 0.510642, + "gen_feat_3": 497.88 + } + }, + { + "id": "t_get_closest_city_gen_4", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 493.82, + "gen_feat_2": 0.509042, + "gen_feat_3": 492.58 + } + }, + { + "id": "t_get_closest_city_gen_5", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_1", + "name": "getClosestCity (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 485.83, + "gen_feat_2": 0.508367, + "gen_feat_3": 502.67 + } + }, + { + "id": "t_get_closest_city_gen_6", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_2", + "name": "getClosestCity (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 510.35, + "gen_feat_2": 0.507866, + "gen_feat_3": 485.56 + } + }, + { + "id": "t_get_closest_city_gen_7", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_3", + "name": "getClosestCity (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 506.43, + "gen_feat_2": 0.485825, + "gen_feat_3": 496.36 + } + }, + { + "id": "t_get_closest_city_gen_8", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 511.75, + "gen_feat_2": 0.497873, + "gen_feat_3": 487.86 + } + }, + { + "id": "t_get_closest_city_gen_9", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 489.25, + "gen_feat_2": 0.493981, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_2", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 513.51, + "gen_feat_2": 0.496631, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_get_local_subsidiary_gen_3", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 493.1, + "gen_feat_2": 0.495292, + "gen_feat_3": 510.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_4", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_2", + "name": "getLocalSubsidiary (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 490.37, + "gen_feat_2": 0.513325, + "gen_feat_3": 498.92 + } + }, + { + "id": "t_get_local_subsidiary_gen_5", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_3", + "name": "getLocalSubsidiary (Gen p_gen_3)", + "features": { + "cost": 1.0, + "gen_feat_1": 502.56, + "gen_feat_2": 0.499451, + "gen_feat_3": 508.64 + } + }, + { + "id": "t_get_local_subsidiary_gen_6", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_4", + "name": "getLocalSubsidiary (Gen p_gen_4)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.52, + "gen_feat_2": 0.505343, + "gen_feat_3": 497.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_7", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_5", + "name": "getLocalSubsidiary (Gen p_gen_5)", + "features": { + "cost": 0.97, + "gen_feat_1": 508.83, + "gen_feat_2": 0.505122, + "gen_feat_3": 493.09 + } + }, + { + "id": "t_get_local_subsidiary_gen_8", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.02, + "gen_feat_1": 498.4, + "gen_feat_2": 0.51387, + "gen_feat_3": 507.57 + } + }, + { + "id": "t_get_local_subsidiary_gen_9", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.29, + "gen_feat_2": 0.501427, + "gen_feat_3": 499.52 + } + }, + { + "id": "t_get_vehicle_gen_2", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 489.79, + "gen_feat_2": 0.496462, + "gen_feat_3": 494.94 + } + }, + { + "id": "t_get_vehicle_gen_3", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 0.99, + "gen_feat_1": 487.88, + "gen_feat_2": 0.493816, + "gen_feat_3": 501.37 + } + }, + { + "id": "t_get_vehicle_gen_4", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_4", + "name": "getVehicle (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 498.07, + "gen_feat_2": 0.509826, + "gen_feat_3": 513.13 + } + }, + { + "id": "t_get_vehicle_gen_5", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_5", + "name": "getVehicle (Gen p_gen_5)", + "features": { + "cost": 1.03, + "gen_feat_1": 503.58, + "gen_feat_2": 0.508911, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_get_vehicle_gen_6", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle (Gen p_transport_agency)", + "features": { + "cost": 0.99, + "gen_feat_1": 510.19, + "gen_feat_2": 0.504186, + "gen_feat_3": 511.03 + } + }, + { + "id": "t_get_vehicle_gen_7", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_1", + "name": "getVehicle (Gen p_gen_1)", + "features": { + "cost": 1.0, + "gen_feat_1": 503.59, + "gen_feat_2": 0.488626, + "gen_feat_3": 505.75 + } + }, + { + "id": "t_get_vehicle_gen_8", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 503.39, + "gen_feat_2": 0.487699, + "gen_feat_3": 511.79 + } + }, + { + "id": "t_get_vehicle_gen_9", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 512.8, + "gen_feat_2": 0.503185, + "gen_feat_3": 496.01 + } + }, + { + "id": "t_make_arrangements_gen_2", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 492.14, + "gen_feat_2": 0.488787, + "gen_feat_3": 502.39 + } + }, + { + "id": "t_make_arrangements_gen_3", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 494.15, + "gen_feat_2": 0.501903, + "gen_feat_3": 504.55 + } + }, + { + "id": "t_make_arrangements_gen_4", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.81, + "gen_feat_2": 0.488585, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_make_arrangements_gen_5", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_1", + "name": "makeArrangements (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.66, + "gen_feat_2": 0.486683, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_make_arrangements_gen_6", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_2", + "name": "makeArrangements (Gen p_gen_2)", + "features": { + "cost": 1.0, + "gen_feat_1": 513.24, + "gen_feat_2": 0.493676, + "gen_feat_3": 494.85 + } + }, + { + "id": "t_make_arrangements_gen_7", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_3", + "name": "makeArrangements (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513493, + "gen_feat_3": 496.34 + } + }, + { + "id": "t_make_arrangements_gen_8", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 0.99, + "gen_feat_1": 513.6, + "gen_feat_2": 0.503479, + "gen_feat_3": 494.88 + } + }, + { + "id": "t_make_arrangements_gen_9", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 510.22, + "gen_feat_2": 0.498065, + "gen_feat_3": 500.63 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_country", + "kind": "TASK", + "task_id": "t_get_country_from_location" + }, + { + "id": "n_company", + "kind": "TASK", + "task_id": "t_get_transport_company" + }, + { + "id": "n_city", + "kind": "TASK", + "task_id": "t_get_closest_city" + }, + { + "id": "n_subsidiary", + "kind": "TASK", + "task_id": "t_get_local_subsidiary" + }, + { + "id": "n_vehicle", + "kind": "TASK", + "task_id": "t_get_vehicle" + }, + { + "id": "n_arrangements", + "kind": "TASK", + "task_id": "t_make_arrangements" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "cost", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3" + ], + "weights": { + "cost": 0.25, + "gen_feat_1": 0.25, + "gen_feat_2": 0.25, + "gen_feat_3": 0.25 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 6.01, + "hard": true + }, + { + "id": "gen_c_local_t_get_closest_city_gen_feat_1_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_get_closest_city" + ], + "attribute_id": "gen_feat_1", + "op": "<=", + "value": 497.52, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_get_country_from_location" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_make_arrangements" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/netedu2020-transport-agency_mono_utility_soft.json b/experimentation/instances/netedu2020-transport-agency_mono_utility_soft.json new file mode 100644 index 0000000..b5f3f94 --- /dev/null +++ b/experimentation/instances/netedu2020-transport-agency_mono_utility_soft.json @@ -0,0 +1,977 @@ +{ + "metadata": { + "id": "netedu2020-transport-agency_mono_utility_soft", + "name": "Transport Agency case study (Netedu et al. 2020) [mono_utility, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Models the running example from 'A Web Service Composition Method Based on OpenAPI Semantic Annotations' (Netedu et al., 2020), Sect. 5 Case Study: A Transport Agency. QoS values are not provided in the paper; a minimal 'cost' feature is added for schema compliance.", + "paper": { + "title": "A Web Service Composition Method Based on OpenAPI Semantic Annotations", + "authors": "A. Netedu et al.", + "year": 2020, + "doi": "10.1007/978-3-030-34986-8_25" + } + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "USD", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_transport_agency", + "name": "Transport Agency REST API" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_get_country_from_location", + "name": "getCountryFromLocation" + }, + { + "id": "t_get_transport_company", + "name": "getTransportCompany" + }, + { + "id": "t_get_closest_city", + "name": "getClosestCity" + }, + { + "id": "t_get_local_subsidiary", + "name": "getLocalSubsidiary" + }, + { + "id": "t_get_vehicle", + "name": "getVehicle" + }, + { + "id": "t_make_arrangements", + "name": "makeArrangements" + } + ], + "candidates": [ + { + "id": "c_get_country_from_location", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_transport_company", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_closest_city", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_local_subsidiary", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_vehicle", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_make_arrangements", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_get_country_from_location_gen_1", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_shared", + "name": "getCountryFromLocation (Gen Shared)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.04, + "gen_feat_2": 0.513114, + "gen_feat_3": 485.63 + } + }, + { + "id": "t_get_transport_company_gen_1", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_shared", + "name": "getTransportCompany (Gen Shared)", + "features": { + "cost": 0.99, + "gen_feat_1": 506.99, + "gen_feat_2": 0.503453, + "gen_feat_3": 502.41 + } + }, + { + "id": "t_get_closest_city_gen_1", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_shared", + "name": "getClosestCity (Gen Shared)", + "features": { + "cost": 1.02, + "gen_feat_1": 497.52, + "gen_feat_2": 0.503882, + "gen_feat_3": 496.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_1", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_shared", + "name": "getLocalSubsidiary (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 512.34, + "gen_feat_2": 0.489132, + "gen_feat_3": 506.11 + } + }, + { + "id": "t_get_vehicle_gen_1", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_shared", + "name": "getVehicle (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 502.66, + "gen_feat_2": 0.509316, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_make_arrangements_gen_1", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_shared", + "name": "makeArrangements (Gen Shared)", + "features": { + "cost": 1.03, + "gen_feat_1": 489.65, + "gen_feat_2": 0.485293, + "gen_feat_3": 513.91 + } + }, + { + "id": "t_get_country_from_location_gen_2", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 0.98, + "gen_feat_1": 487.4, + "gen_feat_2": 0.511921, + "gen_feat_3": 508.92 + } + }, + { + "id": "t_get_country_from_location_gen_3", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500027, + "gen_feat_3": 507.17 + } + }, + { + "id": "t_get_country_from_location_gen_4", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_2", + "name": "getCountryFromLocation (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 504.84, + "gen_feat_2": 0.508391, + "gen_feat_3": 492.85 + } + }, + { + "id": "t_get_country_from_location_gen_5", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_3", + "name": "getCountryFromLocation (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.58, + "gen_feat_2": 0.512949, + "gen_feat_3": 506.57 + } + }, + { + "id": "t_get_country_from_location_gen_6", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_4", + "name": "getCountryFromLocation (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 501.88, + "gen_feat_2": 0.494867, + "gen_feat_3": 507.59 + } + }, + { + "id": "t_get_country_from_location_gen_7", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_5", + "name": "getCountryFromLocation (Gen p_gen_5)", + "features": { + "cost": 0.99, + "gen_feat_1": 507.26, + "gen_feat_2": 0.491882, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_get_country_from_location_gen_8", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 506.26, + "gen_feat_2": 0.510131, + "gen_feat_3": 505.7 + } + }, + { + "id": "t_get_country_from_location_gen_9", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 486.8, + "gen_feat_2": 0.510302, + "gen_feat_3": 507.54 + } + }, + { + "id": "t_get_transport_company_gen_2", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 505.78, + "gen_feat_2": 0.498526, + "gen_feat_3": 487.5 + } + }, + { + "id": "t_get_transport_company_gen_3", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 510.84, + "gen_feat_2": 0.506966, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_get_transport_company_gen_4", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_4", + "name": "getTransportCompany (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 503.48, + "gen_feat_2": 0.500194, + "gen_feat_3": 504.85 + } + }, + { + "id": "t_get_transport_company_gen_5", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_5", + "name": "getTransportCompany (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 493.49, + "gen_feat_2": 0.491039, + "gen_feat_3": 486.86 + } + }, + { + "id": "t_get_transport_company_gen_6", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 499.16, + "gen_feat_2": 0.495989, + "gen_feat_3": 512.41 + } + }, + { + "id": "t_get_transport_company_gen_7", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_1", + "name": "getTransportCompany (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 502.63, + "gen_feat_2": 0.506883, + "gen_feat_3": 507.66 + } + }, + { + "id": "t_get_transport_company_gen_8", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 491.72, + "gen_feat_2": 0.493913, + "gen_feat_3": 499.04 + } + }, + { + "id": "t_get_transport_company_gen_9", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 511.11, + "gen_feat_2": 0.49489, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_get_closest_city_gen_2", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 0.98, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514837, + "gen_feat_3": 502.45 + } + }, + { + "id": "t_get_closest_city_gen_3", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.16, + "gen_feat_2": 0.510642, + "gen_feat_3": 497.88 + } + }, + { + "id": "t_get_closest_city_gen_4", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 493.82, + "gen_feat_2": 0.509042, + "gen_feat_3": 492.58 + } + }, + { + "id": "t_get_closest_city_gen_5", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_1", + "name": "getClosestCity (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 485.83, + "gen_feat_2": 0.508367, + "gen_feat_3": 502.67 + } + }, + { + "id": "t_get_closest_city_gen_6", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_2", + "name": "getClosestCity (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 510.35, + "gen_feat_2": 0.507866, + "gen_feat_3": 485.56 + } + }, + { + "id": "t_get_closest_city_gen_7", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_3", + "name": "getClosestCity (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 506.43, + "gen_feat_2": 0.485825, + "gen_feat_3": 496.36 + } + }, + { + "id": "t_get_closest_city_gen_8", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 511.75, + "gen_feat_2": 0.497873, + "gen_feat_3": 487.86 + } + }, + { + "id": "t_get_closest_city_gen_9", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 489.25, + "gen_feat_2": 0.493981, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_2", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 513.51, + "gen_feat_2": 0.496631, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_get_local_subsidiary_gen_3", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 493.1, + "gen_feat_2": 0.495292, + "gen_feat_3": 510.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_4", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_2", + "name": "getLocalSubsidiary (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 490.37, + "gen_feat_2": 0.513325, + "gen_feat_3": 498.92 + } + }, + { + "id": "t_get_local_subsidiary_gen_5", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_3", + "name": "getLocalSubsidiary (Gen p_gen_3)", + "features": { + "cost": 1.0, + "gen_feat_1": 502.56, + "gen_feat_2": 0.499451, + "gen_feat_3": 508.64 + } + }, + { + "id": "t_get_local_subsidiary_gen_6", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_4", + "name": "getLocalSubsidiary (Gen p_gen_4)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.52, + "gen_feat_2": 0.505343, + "gen_feat_3": 497.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_7", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_5", + "name": "getLocalSubsidiary (Gen p_gen_5)", + "features": { + "cost": 0.97, + "gen_feat_1": 508.83, + "gen_feat_2": 0.505122, + "gen_feat_3": 493.09 + } + }, + { + "id": "t_get_local_subsidiary_gen_8", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.02, + "gen_feat_1": 498.4, + "gen_feat_2": 0.51387, + "gen_feat_3": 507.57 + } + }, + { + "id": "t_get_local_subsidiary_gen_9", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.29, + "gen_feat_2": 0.501427, + "gen_feat_3": 499.52 + } + }, + { + "id": "t_get_vehicle_gen_2", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 489.79, + "gen_feat_2": 0.496462, + "gen_feat_3": 494.94 + } + }, + { + "id": "t_get_vehicle_gen_3", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 0.99, + "gen_feat_1": 487.88, + "gen_feat_2": 0.493816, + "gen_feat_3": 501.37 + } + }, + { + "id": "t_get_vehicle_gen_4", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_4", + "name": "getVehicle (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 498.07, + "gen_feat_2": 0.509826, + "gen_feat_3": 513.13 + } + }, + { + "id": "t_get_vehicle_gen_5", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_5", + "name": "getVehicle (Gen p_gen_5)", + "features": { + "cost": 1.03, + "gen_feat_1": 503.58, + "gen_feat_2": 0.508911, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_get_vehicle_gen_6", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle (Gen p_transport_agency)", + "features": { + "cost": 0.99, + "gen_feat_1": 510.19, + "gen_feat_2": 0.504186, + "gen_feat_3": 511.03 + } + }, + { + "id": "t_get_vehicle_gen_7", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_1", + "name": "getVehicle (Gen p_gen_1)", + "features": { + "cost": 1.0, + "gen_feat_1": 503.59, + "gen_feat_2": 0.488626, + "gen_feat_3": 505.75 + } + }, + { + "id": "t_get_vehicle_gen_8", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 503.39, + "gen_feat_2": 0.487699, + "gen_feat_3": 511.79 + } + }, + { + "id": "t_get_vehicle_gen_9", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 512.8, + "gen_feat_2": 0.503185, + "gen_feat_3": 496.01 + } + }, + { + "id": "t_make_arrangements_gen_2", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 492.14, + "gen_feat_2": 0.488787, + "gen_feat_3": 502.39 + } + }, + { + "id": "t_make_arrangements_gen_3", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 494.15, + "gen_feat_2": 0.501903, + "gen_feat_3": 504.55 + } + }, + { + "id": "t_make_arrangements_gen_4", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.81, + "gen_feat_2": 0.488585, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_make_arrangements_gen_5", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_1", + "name": "makeArrangements (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.66, + "gen_feat_2": 0.486683, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_make_arrangements_gen_6", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_2", + "name": "makeArrangements (Gen p_gen_2)", + "features": { + "cost": 1.0, + "gen_feat_1": 513.24, + "gen_feat_2": 0.493676, + "gen_feat_3": 494.85 + } + }, + { + "id": "t_make_arrangements_gen_7", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_3", + "name": "makeArrangements (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513493, + "gen_feat_3": 496.34 + } + }, + { + "id": "t_make_arrangements_gen_8", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 0.99, + "gen_feat_1": 513.6, + "gen_feat_2": 0.503479, + "gen_feat_3": 494.88 + } + }, + { + "id": "t_make_arrangements_gen_9", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 510.22, + "gen_feat_2": 0.498065, + "gen_feat_3": 500.63 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_country", + "kind": "TASK", + "task_id": "t_get_country_from_location" + }, + { + "id": "n_company", + "kind": "TASK", + "task_id": "t_get_transport_company" + }, + { + "id": "n_city", + "kind": "TASK", + "task_id": "t_get_closest_city" + }, + { + "id": "n_subsidiary", + "kind": "TASK", + "task_id": "t_get_local_subsidiary" + }, + { + "id": "n_vehicle", + "kind": "TASK", + "task_id": "t_get_vehicle" + }, + { + "id": "n_arrangements", + "kind": "TASK", + "task_id": "t_make_arrangements" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + } + }, + "objective": { + "type": "MONO", + "targets": [ + "cost", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3" + ], + "weights": { + "cost": 0.25, + "gen_feat_1": 0.25, + "gen_feat_2": 0.25, + "gen_feat_3": 0.25 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 6.01, + "hard": false + }, + { + "id": "gen_c_local_t_get_closest_city_gen_feat_1_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_get_closest_city" + ], + "attribute_id": "gen_feat_1", + "op": "<=", + "value": 497.52, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_get_country_from_location" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_make_arrangements" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/netedu2020-transport-agency_multi_hard.json b/experimentation/instances/netedu2020-transport-agency_multi_hard.json new file mode 100644 index 0000000..04aa3a5 --- /dev/null +++ b/experimentation/instances/netedu2020-transport-agency_multi_hard.json @@ -0,0 +1,975 @@ +{ + "metadata": { + "id": "netedu2020-transport-agency_multi_hard", + "name": "Transport Agency case study (Netedu et al. 2020) [multi, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Models the running example from 'A Web Service Composition Method Based on OpenAPI Semantic Annotations' (Netedu et al., 2020), Sect. 5 Case Study: A Transport Agency. QoS values are not provided in the paper; a minimal 'cost' feature is added for schema compliance.", + "paper": { + "title": "A Web Service Composition Method Based on OpenAPI Semantic Annotations", + "authors": "A. Netedu et al.", + "year": 2020, + "doi": "10.1007/978-3-030-34986-8_25" + } + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "USD", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_transport_agency", + "name": "Transport Agency REST API" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_get_country_from_location", + "name": "getCountryFromLocation" + }, + { + "id": "t_get_transport_company", + "name": "getTransportCompany" + }, + { + "id": "t_get_closest_city", + "name": "getClosestCity" + }, + { + "id": "t_get_local_subsidiary", + "name": "getLocalSubsidiary" + }, + { + "id": "t_get_vehicle", + "name": "getVehicle" + }, + { + "id": "t_make_arrangements", + "name": "makeArrangements" + } + ], + "candidates": [ + { + "id": "c_get_country_from_location", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_transport_company", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_closest_city", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_local_subsidiary", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_vehicle", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_make_arrangements", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_get_country_from_location_gen_1", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_shared", + "name": "getCountryFromLocation (Gen Shared)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.04, + "gen_feat_2": 0.513114, + "gen_feat_3": 485.63 + } + }, + { + "id": "t_get_transport_company_gen_1", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_shared", + "name": "getTransportCompany (Gen Shared)", + "features": { + "cost": 0.99, + "gen_feat_1": 506.99, + "gen_feat_2": 0.503453, + "gen_feat_3": 502.41 + } + }, + { + "id": "t_get_closest_city_gen_1", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_shared", + "name": "getClosestCity (Gen Shared)", + "features": { + "cost": 1.02, + "gen_feat_1": 497.52, + "gen_feat_2": 0.503882, + "gen_feat_3": 496.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_1", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_shared", + "name": "getLocalSubsidiary (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 512.34, + "gen_feat_2": 0.489132, + "gen_feat_3": 506.11 + } + }, + { + "id": "t_get_vehicle_gen_1", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_shared", + "name": "getVehicle (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 502.66, + "gen_feat_2": 0.509316, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_make_arrangements_gen_1", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_shared", + "name": "makeArrangements (Gen Shared)", + "features": { + "cost": 1.03, + "gen_feat_1": 489.65, + "gen_feat_2": 0.485293, + "gen_feat_3": 513.91 + } + }, + { + "id": "t_get_country_from_location_gen_2", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 0.98, + "gen_feat_1": 487.4, + "gen_feat_2": 0.511921, + "gen_feat_3": 508.92 + } + }, + { + "id": "t_get_country_from_location_gen_3", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500027, + "gen_feat_3": 507.17 + } + }, + { + "id": "t_get_country_from_location_gen_4", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_2", + "name": "getCountryFromLocation (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 504.84, + "gen_feat_2": 0.508391, + "gen_feat_3": 492.85 + } + }, + { + "id": "t_get_country_from_location_gen_5", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_3", + "name": "getCountryFromLocation (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.58, + "gen_feat_2": 0.512949, + "gen_feat_3": 506.57 + } + }, + { + "id": "t_get_country_from_location_gen_6", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_4", + "name": "getCountryFromLocation (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 501.88, + "gen_feat_2": 0.494867, + "gen_feat_3": 507.59 + } + }, + { + "id": "t_get_country_from_location_gen_7", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_5", + "name": "getCountryFromLocation (Gen p_gen_5)", + "features": { + "cost": 0.99, + "gen_feat_1": 507.26, + "gen_feat_2": 0.491882, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_get_country_from_location_gen_8", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 506.26, + "gen_feat_2": 0.510131, + "gen_feat_3": 505.7 + } + }, + { + "id": "t_get_country_from_location_gen_9", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 486.8, + "gen_feat_2": 0.510302, + "gen_feat_3": 507.54 + } + }, + { + "id": "t_get_transport_company_gen_2", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 505.78, + "gen_feat_2": 0.498526, + "gen_feat_3": 487.5 + } + }, + { + "id": "t_get_transport_company_gen_3", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 510.84, + "gen_feat_2": 0.506966, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_get_transport_company_gen_4", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_4", + "name": "getTransportCompany (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 503.48, + "gen_feat_2": 0.500194, + "gen_feat_3": 504.85 + } + }, + { + "id": "t_get_transport_company_gen_5", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_5", + "name": "getTransportCompany (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 493.49, + "gen_feat_2": 0.491039, + "gen_feat_3": 486.86 + } + }, + { + "id": "t_get_transport_company_gen_6", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 499.16, + "gen_feat_2": 0.495989, + "gen_feat_3": 512.41 + } + }, + { + "id": "t_get_transport_company_gen_7", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_1", + "name": "getTransportCompany (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 502.63, + "gen_feat_2": 0.506883, + "gen_feat_3": 507.66 + } + }, + { + "id": "t_get_transport_company_gen_8", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 491.72, + "gen_feat_2": 0.493913, + "gen_feat_3": 499.04 + } + }, + { + "id": "t_get_transport_company_gen_9", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 511.11, + "gen_feat_2": 0.49489, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_get_closest_city_gen_2", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 0.98, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514837, + "gen_feat_3": 502.45 + } + }, + { + "id": "t_get_closest_city_gen_3", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.16, + "gen_feat_2": 0.510642, + "gen_feat_3": 497.88 + } + }, + { + "id": "t_get_closest_city_gen_4", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 493.82, + "gen_feat_2": 0.509042, + "gen_feat_3": 492.58 + } + }, + { + "id": "t_get_closest_city_gen_5", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_1", + "name": "getClosestCity (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 485.83, + "gen_feat_2": 0.508367, + "gen_feat_3": 502.67 + } + }, + { + "id": "t_get_closest_city_gen_6", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_2", + "name": "getClosestCity (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 510.35, + "gen_feat_2": 0.507866, + "gen_feat_3": 485.56 + } + }, + { + "id": "t_get_closest_city_gen_7", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_3", + "name": "getClosestCity (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 506.43, + "gen_feat_2": 0.485825, + "gen_feat_3": 496.36 + } + }, + { + "id": "t_get_closest_city_gen_8", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 511.75, + "gen_feat_2": 0.497873, + "gen_feat_3": 487.86 + } + }, + { + "id": "t_get_closest_city_gen_9", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 489.25, + "gen_feat_2": 0.493981, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_2", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 513.51, + "gen_feat_2": 0.496631, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_get_local_subsidiary_gen_3", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 493.1, + "gen_feat_2": 0.495292, + "gen_feat_3": 510.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_4", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_2", + "name": "getLocalSubsidiary (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 490.37, + "gen_feat_2": 0.513325, + "gen_feat_3": 498.92 + } + }, + { + "id": "t_get_local_subsidiary_gen_5", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_3", + "name": "getLocalSubsidiary (Gen p_gen_3)", + "features": { + "cost": 1.0, + "gen_feat_1": 502.56, + "gen_feat_2": 0.499451, + "gen_feat_3": 508.64 + } + }, + { + "id": "t_get_local_subsidiary_gen_6", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_4", + "name": "getLocalSubsidiary (Gen p_gen_4)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.52, + "gen_feat_2": 0.505343, + "gen_feat_3": 497.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_7", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_5", + "name": "getLocalSubsidiary (Gen p_gen_5)", + "features": { + "cost": 0.97, + "gen_feat_1": 508.83, + "gen_feat_2": 0.505122, + "gen_feat_3": 493.09 + } + }, + { + "id": "t_get_local_subsidiary_gen_8", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.02, + "gen_feat_1": 498.4, + "gen_feat_2": 0.51387, + "gen_feat_3": 507.57 + } + }, + { + "id": "t_get_local_subsidiary_gen_9", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.29, + "gen_feat_2": 0.501427, + "gen_feat_3": 499.52 + } + }, + { + "id": "t_get_vehicle_gen_2", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 489.79, + "gen_feat_2": 0.496462, + "gen_feat_3": 494.94 + } + }, + { + "id": "t_get_vehicle_gen_3", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 0.99, + "gen_feat_1": 487.88, + "gen_feat_2": 0.493816, + "gen_feat_3": 501.37 + } + }, + { + "id": "t_get_vehicle_gen_4", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_4", + "name": "getVehicle (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 498.07, + "gen_feat_2": 0.509826, + "gen_feat_3": 513.13 + } + }, + { + "id": "t_get_vehicle_gen_5", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_5", + "name": "getVehicle (Gen p_gen_5)", + "features": { + "cost": 1.03, + "gen_feat_1": 503.58, + "gen_feat_2": 0.508911, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_get_vehicle_gen_6", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle (Gen p_transport_agency)", + "features": { + "cost": 0.99, + "gen_feat_1": 510.19, + "gen_feat_2": 0.504186, + "gen_feat_3": 511.03 + } + }, + { + "id": "t_get_vehicle_gen_7", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_1", + "name": "getVehicle (Gen p_gen_1)", + "features": { + "cost": 1.0, + "gen_feat_1": 503.59, + "gen_feat_2": 0.488626, + "gen_feat_3": 505.75 + } + }, + { + "id": "t_get_vehicle_gen_8", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 503.39, + "gen_feat_2": 0.487699, + "gen_feat_3": 511.79 + } + }, + { + "id": "t_get_vehicle_gen_9", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 512.8, + "gen_feat_2": 0.503185, + "gen_feat_3": 496.01 + } + }, + { + "id": "t_make_arrangements_gen_2", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 492.14, + "gen_feat_2": 0.488787, + "gen_feat_3": 502.39 + } + }, + { + "id": "t_make_arrangements_gen_3", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 494.15, + "gen_feat_2": 0.501903, + "gen_feat_3": 504.55 + } + }, + { + "id": "t_make_arrangements_gen_4", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.81, + "gen_feat_2": 0.488585, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_make_arrangements_gen_5", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_1", + "name": "makeArrangements (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.66, + "gen_feat_2": 0.486683, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_make_arrangements_gen_6", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_2", + "name": "makeArrangements (Gen p_gen_2)", + "features": { + "cost": 1.0, + "gen_feat_1": 513.24, + "gen_feat_2": 0.493676, + "gen_feat_3": 494.85 + } + }, + { + "id": "t_make_arrangements_gen_7", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_3", + "name": "makeArrangements (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513493, + "gen_feat_3": 496.34 + } + }, + { + "id": "t_make_arrangements_gen_8", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 0.99, + "gen_feat_1": 513.6, + "gen_feat_2": 0.503479, + "gen_feat_3": 494.88 + } + }, + { + "id": "t_make_arrangements_gen_9", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 510.22, + "gen_feat_2": 0.498065, + "gen_feat_3": 500.63 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_country", + "kind": "TASK", + "task_id": "t_get_country_from_location" + }, + { + "id": "n_company", + "kind": "TASK", + "task_id": "t_get_transport_company" + }, + { + "id": "n_city", + "kind": "TASK", + "task_id": "t_get_closest_city" + }, + { + "id": "n_subsidiary", + "kind": "TASK", + "task_id": "t_get_local_subsidiary" + }, + { + "id": "n_vehicle", + "kind": "TASK", + "task_id": "t_get_vehicle" + }, + { + "id": "n_arrangements", + "kind": "TASK", + "task_id": "t_make_arrangements" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + } + }, + "objective": { + "type": "MULTI", + "targets": [ + "cost", + "gen_feat_1", + "gen_feat_2" + ], + "weights": { + "cost": 0.34, + "gen_feat_1": 0.33, + "gen_feat_2": 0.33 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 6.01, + "hard": true + }, + { + "id": "gen_c_local_t_get_closest_city_gen_feat_1_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_get_closest_city" + ], + "attribute_id": "gen_feat_1", + "op": "<=", + "value": 497.52, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_get_country_from_location" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_make_arrangements" + ], + "hard": true + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/netedu2020-transport-agency_multi_soft.json b/experimentation/instances/netedu2020-transport-agency_multi_soft.json new file mode 100644 index 0000000..4166e24 --- /dev/null +++ b/experimentation/instances/netedu2020-transport-agency_multi_soft.json @@ -0,0 +1,975 @@ +{ + "metadata": { + "id": "netedu2020-transport-agency_multi_soft", + "name": "Transport Agency case study (Netedu et al. 2020) [multi, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:55Z", + "description": "Models the running example from 'A Web Service Composition Method Based on OpenAPI Semantic Annotations' (Netedu et al., 2020), Sect. 5 Case Study: A Transport Agency. QoS values are not provided in the paper; a minimal 'cost' feature is added for schema compliance.", + "paper": { + "title": "A Web Service Composition Method Based on OpenAPI Semantic Annotations", + "authors": "A. Netedu et al.", + "year": 2020, + "doi": "10.1007/978-3-030-34986-8_25" + } + }, + "features": [ + { + "id": "cost", + "name": "Cost", + "direction": "MINIMIZE", + "unit": "USD", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_transport_agency", + "name": "Transport Agency REST API" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_get_country_from_location", + "name": "getCountryFromLocation" + }, + { + "id": "t_get_transport_company", + "name": "getTransportCompany" + }, + { + "id": "t_get_closest_city", + "name": "getClosestCity" + }, + { + "id": "t_get_local_subsidiary", + "name": "getLocalSubsidiary" + }, + { + "id": "t_get_vehicle", + "name": "getVehicle" + }, + { + "id": "t_make_arrangements", + "name": "makeArrangements" + } + ], + "candidates": [ + { + "id": "c_get_country_from_location", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_transport_company", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_closest_city", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_local_subsidiary", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_get_vehicle", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_make_arrangements", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements", + "features": { + "cost": 1, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_get_country_from_location_gen_1", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_shared", + "name": "getCountryFromLocation (Gen Shared)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.04, + "gen_feat_2": 0.513114, + "gen_feat_3": 485.63 + } + }, + { + "id": "t_get_transport_company_gen_1", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_shared", + "name": "getTransportCompany (Gen Shared)", + "features": { + "cost": 0.99, + "gen_feat_1": 506.99, + "gen_feat_2": 0.503453, + "gen_feat_3": 502.41 + } + }, + { + "id": "t_get_closest_city_gen_1", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_shared", + "name": "getClosestCity (Gen Shared)", + "features": { + "cost": 1.02, + "gen_feat_1": 497.52, + "gen_feat_2": 0.503882, + "gen_feat_3": 496.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_1", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_shared", + "name": "getLocalSubsidiary (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 512.34, + "gen_feat_2": 0.489132, + "gen_feat_3": 506.11 + } + }, + { + "id": "t_get_vehicle_gen_1", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_shared", + "name": "getVehicle (Gen Shared)", + "features": { + "cost": 1.01, + "gen_feat_1": 502.66, + "gen_feat_2": 0.509316, + "gen_feat_3": 503.99 + } + }, + { + "id": "t_make_arrangements_gen_1", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_shared", + "name": "makeArrangements (Gen Shared)", + "features": { + "cost": 1.03, + "gen_feat_1": 489.65, + "gen_feat_2": 0.485293, + "gen_feat_3": 513.91 + } + }, + { + "id": "t_get_country_from_location_gen_2", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 0.98, + "gen_feat_1": 487.4, + "gen_feat_2": 0.511921, + "gen_feat_3": 508.92 + } + }, + { + "id": "t_get_country_from_location_gen_3", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500027, + "gen_feat_3": 507.17 + } + }, + { + "id": "t_get_country_from_location_gen_4", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_2", + "name": "getCountryFromLocation (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 504.84, + "gen_feat_2": 0.508391, + "gen_feat_3": 492.85 + } + }, + { + "id": "t_get_country_from_location_gen_5", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_3", + "name": "getCountryFromLocation (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.58, + "gen_feat_2": 0.512949, + "gen_feat_3": 506.57 + } + }, + { + "id": "t_get_country_from_location_gen_6", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_4", + "name": "getCountryFromLocation (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 501.88, + "gen_feat_2": 0.494867, + "gen_feat_3": 507.59 + } + }, + { + "id": "t_get_country_from_location_gen_7", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_5", + "name": "getCountryFromLocation (Gen p_gen_5)", + "features": { + "cost": 0.99, + "gen_feat_1": 507.26, + "gen_feat_2": 0.491882, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_get_country_from_location_gen_8", + "task_id": "t_get_country_from_location", + "provider_id": "p_transport_agency", + "name": "getCountryFromLocation (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 506.26, + "gen_feat_2": 0.510131, + "gen_feat_3": 505.7 + } + }, + { + "id": "t_get_country_from_location_gen_9", + "task_id": "t_get_country_from_location", + "provider_id": "p_gen_1", + "name": "getCountryFromLocation (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 486.8, + "gen_feat_2": 0.510302, + "gen_feat_3": 507.54 + } + }, + { + "id": "t_get_transport_company_gen_2", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 505.78, + "gen_feat_2": 0.498526, + "gen_feat_3": 487.5 + } + }, + { + "id": "t_get_transport_company_gen_3", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 510.84, + "gen_feat_2": 0.506966, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_get_transport_company_gen_4", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_4", + "name": "getTransportCompany (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 503.48, + "gen_feat_2": 0.500194, + "gen_feat_3": 504.85 + } + }, + { + "id": "t_get_transport_company_gen_5", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_5", + "name": "getTransportCompany (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 493.49, + "gen_feat_2": 0.491039, + "gen_feat_3": 486.86 + } + }, + { + "id": "t_get_transport_company_gen_6", + "task_id": "t_get_transport_company", + "provider_id": "p_transport_agency", + "name": "getTransportCompany (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 499.16, + "gen_feat_2": 0.495989, + "gen_feat_3": 512.41 + } + }, + { + "id": "t_get_transport_company_gen_7", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_1", + "name": "getTransportCompany (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 502.63, + "gen_feat_2": 0.506883, + "gen_feat_3": 507.66 + } + }, + { + "id": "t_get_transport_company_gen_8", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_2", + "name": "getTransportCompany (Gen p_gen_2)", + "features": { + "cost": 0.98, + "gen_feat_1": 491.72, + "gen_feat_2": 0.493913, + "gen_feat_3": 499.04 + } + }, + { + "id": "t_get_transport_company_gen_9", + "task_id": "t_get_transport_company", + "provider_id": "p_gen_3", + "name": "getTransportCompany (Gen p_gen_3)", + "features": { + "cost": 0.98, + "gen_feat_1": 511.11, + "gen_feat_2": 0.49489, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_get_closest_city_gen_2", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 0.98, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514837, + "gen_feat_3": 502.45 + } + }, + { + "id": "t_get_closest_city_gen_3", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 513.16, + "gen_feat_2": 0.510642, + "gen_feat_3": 497.88 + } + }, + { + "id": "t_get_closest_city_gen_4", + "task_id": "t_get_closest_city", + "provider_id": "p_transport_agency", + "name": "getClosestCity (Gen p_transport_agency)", + "features": { + "cost": 1.0, + "gen_feat_1": 493.82, + "gen_feat_2": 0.509042, + "gen_feat_3": 492.58 + } + }, + { + "id": "t_get_closest_city_gen_5", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_1", + "name": "getClosestCity (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 485.83, + "gen_feat_2": 0.508367, + "gen_feat_3": 502.67 + } + }, + { + "id": "t_get_closest_city_gen_6", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_2", + "name": "getClosestCity (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 510.35, + "gen_feat_2": 0.507866, + "gen_feat_3": 485.56 + } + }, + { + "id": "t_get_closest_city_gen_7", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_3", + "name": "getClosestCity (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 506.43, + "gen_feat_2": 0.485825, + "gen_feat_3": 496.36 + } + }, + { + "id": "t_get_closest_city_gen_8", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_4", + "name": "getClosestCity (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 511.75, + "gen_feat_2": 0.497873, + "gen_feat_3": 487.86 + } + }, + { + "id": "t_get_closest_city_gen_9", + "task_id": "t_get_closest_city", + "provider_id": "p_gen_5", + "name": "getClosestCity (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 489.25, + "gen_feat_2": 0.493981, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_2", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 513.51, + "gen_feat_2": 0.496631, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_get_local_subsidiary_gen_3", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 0.99, + "gen_feat_1": 493.1, + "gen_feat_2": 0.495292, + "gen_feat_3": 510.66 + } + }, + { + "id": "t_get_local_subsidiary_gen_4", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_2", + "name": "getLocalSubsidiary (Gen p_gen_2)", + "features": { + "cost": 1.02, + "gen_feat_1": 490.37, + "gen_feat_2": 0.513325, + "gen_feat_3": 498.92 + } + }, + { + "id": "t_get_local_subsidiary_gen_5", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_3", + "name": "getLocalSubsidiary (Gen p_gen_3)", + "features": { + "cost": 1.0, + "gen_feat_1": 502.56, + "gen_feat_2": 0.499451, + "gen_feat_3": 508.64 + } + }, + { + "id": "t_get_local_subsidiary_gen_6", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_4", + "name": "getLocalSubsidiary (Gen p_gen_4)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.52, + "gen_feat_2": 0.505343, + "gen_feat_3": 497.93 + } + }, + { + "id": "t_get_local_subsidiary_gen_7", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_5", + "name": "getLocalSubsidiary (Gen p_gen_5)", + "features": { + "cost": 0.97, + "gen_feat_1": 508.83, + "gen_feat_2": 0.505122, + "gen_feat_3": 493.09 + } + }, + { + "id": "t_get_local_subsidiary_gen_8", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_transport_agency", + "name": "getLocalSubsidiary (Gen p_transport_agency)", + "features": { + "cost": 1.02, + "gen_feat_1": 498.4, + "gen_feat_2": 0.51387, + "gen_feat_3": 507.57 + } + }, + { + "id": "t_get_local_subsidiary_gen_9", + "task_id": "t_get_local_subsidiary", + "provider_id": "p_gen_1", + "name": "getLocalSubsidiary (Gen p_gen_1)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.29, + "gen_feat_2": 0.501427, + "gen_feat_3": 499.52 + } + }, + { + "id": "t_get_vehicle_gen_2", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 489.79, + "gen_feat_2": 0.496462, + "gen_feat_3": 494.94 + } + }, + { + "id": "t_get_vehicle_gen_3", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 0.99, + "gen_feat_1": 487.88, + "gen_feat_2": 0.493816, + "gen_feat_3": 501.37 + } + }, + { + "id": "t_get_vehicle_gen_4", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_4", + "name": "getVehicle (Gen p_gen_4)", + "features": { + "cost": 1.0, + "gen_feat_1": 498.07, + "gen_feat_2": 0.509826, + "gen_feat_3": 513.13 + } + }, + { + "id": "t_get_vehicle_gen_5", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_5", + "name": "getVehicle (Gen p_gen_5)", + "features": { + "cost": 1.03, + "gen_feat_1": 503.58, + "gen_feat_2": 0.508911, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_get_vehicle_gen_6", + "task_id": "t_get_vehicle", + "provider_id": "p_transport_agency", + "name": "getVehicle (Gen p_transport_agency)", + "features": { + "cost": 0.99, + "gen_feat_1": 510.19, + "gen_feat_2": 0.504186, + "gen_feat_3": 511.03 + } + }, + { + "id": "t_get_vehicle_gen_7", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_1", + "name": "getVehicle (Gen p_gen_1)", + "features": { + "cost": 1.0, + "gen_feat_1": 503.59, + "gen_feat_2": 0.488626, + "gen_feat_3": 505.75 + } + }, + { + "id": "t_get_vehicle_gen_8", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_2", + "name": "getVehicle (Gen p_gen_2)", + "features": { + "cost": 0.99, + "gen_feat_1": 503.39, + "gen_feat_2": 0.487699, + "gen_feat_3": 511.79 + } + }, + { + "id": "t_get_vehicle_gen_9", + "task_id": "t_get_vehicle", + "provider_id": "p_gen_3", + "name": "getVehicle (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 512.8, + "gen_feat_2": 0.503185, + "gen_feat_3": 496.01 + } + }, + { + "id": "t_make_arrangements_gen_2", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 1.02, + "gen_feat_1": 492.14, + "gen_feat_2": 0.488787, + "gen_feat_3": 502.39 + } + }, + { + "id": "t_make_arrangements_gen_3", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 0.98, + "gen_feat_1": 494.15, + "gen_feat_2": 0.501903, + "gen_feat_3": 504.55 + } + }, + { + "id": "t_make_arrangements_gen_4", + "task_id": "t_make_arrangements", + "provider_id": "p_transport_agency", + "name": "makeArrangements (Gen p_transport_agency)", + "features": { + "cost": 1.01, + "gen_feat_1": 514.81, + "gen_feat_2": 0.488585, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_make_arrangements_gen_5", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_1", + "name": "makeArrangements (Gen p_gen_1)", + "features": { + "cost": 1.01, + "gen_feat_1": 497.66, + "gen_feat_2": 0.486683, + "gen_feat_3": 493.46 + } + }, + { + "id": "t_make_arrangements_gen_6", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_2", + "name": "makeArrangements (Gen p_gen_2)", + "features": { + "cost": 1.0, + "gen_feat_1": 513.24, + "gen_feat_2": 0.493676, + "gen_feat_3": 494.85 + } + }, + { + "id": "t_make_arrangements_gen_7", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_3", + "name": "makeArrangements (Gen p_gen_3)", + "features": { + "cost": 1.02, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513493, + "gen_feat_3": 496.34 + } + }, + { + "id": "t_make_arrangements_gen_8", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_4", + "name": "makeArrangements (Gen p_gen_4)", + "features": { + "cost": 0.99, + "gen_feat_1": 513.6, + "gen_feat_2": 0.503479, + "gen_feat_3": 494.88 + } + }, + { + "id": "t_make_arrangements_gen_9", + "task_id": "t_make_arrangements", + "provider_id": "p_gen_5", + "name": "makeArrangements (Gen p_gen_5)", + "features": { + "cost": 1.01, + "gen_feat_1": 510.22, + "gen_feat_2": 0.498065, + "gen_feat_3": 500.63 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_country", + "kind": "TASK", + "task_id": "t_get_country_from_location" + }, + { + "id": "n_company", + "kind": "TASK", + "task_id": "t_get_transport_company" + }, + { + "id": "n_city", + "kind": "TASK", + "task_id": "t_get_closest_city" + }, + { + "id": "n_subsidiary", + "kind": "TASK", + "task_id": "t_get_local_subsidiary" + }, + { + "id": "n_vehicle", + "kind": "TASK", + "task_id": "t_get_vehicle" + }, + { + "id": "n_arrangements", + "kind": "TASK", + "task_id": "t_make_arrangements" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + } + } + } + }, + "objective": { + "type": "MULTI", + "targets": [ + "cost", + "gen_feat_1", + "gen_feat_2" + ], + "weights": { + "cost": 0.34, + "gen_feat_1": 0.33, + "gen_feat_2": 0.33 + }, + "weights_sum_to_one": true + }, + "constraints": [ + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 6.01, + "hard": false + }, + { + "id": "gen_c_local_t_get_closest_city_gen_feat_1_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_get_closest_city" + ], + "attribute_id": "gen_feat_1", + "op": "<=", + "value": 497.52, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_get_country_from_location" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_get_closest_city", + "t_make_arrangements" + ], + "hard": false + } + ] +} \ No newline at end of file diff --git a/experimentation/instances/pautasso2009-restful-ecommerce_many_hard.json b/experimentation/instances/pautasso2009-restful-ecommerce_many_hard.json new file mode 100644 index 0000000..ffd1c1f --- /dev/null +++ b/experimentation/instances/pautasso2009-restful-ecommerce_many_hard.json @@ -0,0 +1,1083 @@ +{ + "metadata": { + "id": "pautasso2009-restful-ecommerce_many_hard", + "name": "RESTful e-Commerce scenario (Pautasso 2009) [many, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:04Z", + "description": "QoS-aware composition instance derived from the running e-Commerce example in Pautasso (2009) 'BPEL for REST'. QoS numbers are illustrative (the paper specifies the workflow/API but not QoS measurements).", + "paper": { + "title": "RESTful Web service composition with BPEL for REST", + "authors": "C. Pautasso", + "year": 2009, + "doi": "10.1016/j.datak.2009.02.016" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Invocation cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_shop_a", + "name": "Shop Service A" + }, + { + "id": "p_shop_b", + "name": "Shop Service B" + }, + { + "id": "p_catalog_a", + "name": "Catalog Service A" + }, + { + "id": "p_catalog_b", + "name": "Catalog Service B" + }, + { + "id": "p_payment_a", + "name": "Payment Service A" + }, + { + "id": "p_payment_b", + "name": "Payment Service B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_create_order", + "name": "Create order (POST /order)" + }, + { + "id": "t_request_quote", + "name": "Request quote (POST /product/quote)" + }, + { + "id": "t_get_quote", + "name": "Retrieve quote details (GET /quote)" + }, + { + "id": "t_add_item", + "name": "Add line item (POST /order/item)" + }, + { + "id": "t_remove_item", + "name": "Remove line item (DELETE /order/item)" + }, + { + "id": "t_get_amount", + "name": "Get order amount (GET /order/amount)" + }, + { + "id": "t_checkout", + "name": "Checkout (POST /order/payment)" + }, + { + "id": "t_charge_payment", + "name": "Charge payment (POST /payment)" + }, + { + "id": "t_list_confirmed", + "name": "List confirmed orders (GET /order/confirmed)" + }, + { + "id": "t_ship_order", + "name": "Ship order (fulfillment action within Shop binding)" + }, + { + "id": "t_update_shipment", + "name": "Update shipment info (PUT /order/shipment)" + }, + { + "id": "t_cancel_order", + "name": "Cancel order (DELETE /order)" + }, + { + "id": "t_refund_payment", + "name": "Refund payment (DELETE /payment)" + } + ], + "candidates": [ + { + "id": "c_shopA_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_a", + "name": "ShopA POST /order", + "features": { + "latency_ms": 105, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_b", + "name": "ShopB POST /order", + "features": { + "latency_ms": 130, + "cost_usd": 0.0004, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/item", + "features": { + "latency_ms": 135, + "cost_usd": 0.0008, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/item", + "features": { + "latency_ms": 160, + "cost_usd": 0.0006, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order/item", + "features": { + "latency_ms": 85, + "cost_usd": 0.0005, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order/item", + "features": { + "latency_ms": 100, + "cost_usd": 0.0003, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/amount", + "features": { + "latency_ms": 55, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/amount", + "features": { + "latency_ms": 75, + "cost_usd": 0.00018, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/payment", + "features": { + "latency_ms": 150, + "cost_usd": 0.0012, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/payment", + "features": { + "latency_ms": 185, + "cost_usd": 0.001, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/confirmed", + "features": { + "latency_ms": 70, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/confirmed", + "features": { + "latency_ms": 90, + "cost_usd": 0.0002, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_a", + "name": "ShopA fulfillment", + "features": { + "latency_ms": 480, + "cost_usd": 0.05, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_b", + "name": "ShopB fulfillment", + "features": { + "latency_ms": 520, + "cost_usd": 0.045, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_a", + "name": "ShopA PUT /order/shipment", + "features": { + "latency_ms": 95, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_b", + "name": "ShopB PUT /order/shipment", + "features": { + "latency_ms": 110, + "cost_usd": 0.00045, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order", + "features": { + "latency_ms": 85, + "cost_usd": 0.00035, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order", + "features": { + "latency_ms": 95, + "cost_usd": 0.00025, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA POST /product/quote", + "features": { + "latency_ms": 120, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB POST /product/quote", + "features": { + "latency_ms": 210, + "cost_usd": 0.0015, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA GET /quote", + "features": { + "latency_ms": 85, + "cost_usd": 0.001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB GET /quote", + "features": { + "latency_ms": 155, + "cost_usd": 0.0007, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_a", + "name": "PaymentA POST /payment", + "features": { + "latency_ms": 320, + "cost_usd": 0.02, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_b", + "name": "PaymentB POST /payment", + "features": { + "latency_ms": 380, + "cost_usd": 0.017, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_a", + "name": "PaymentA DELETE /payment", + "features": { + "latency_ms": 240, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_b", + "name": "PaymentB DELETE /payment", + "features": { + "latency_ms": 290, + "cost_usd": 0.013, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_create_order_gen_1", + "task_id": "t_create_order", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order (Gen Shared)", + "features": { + "latency_ms": 105.45, + "cost_usd": 0.0, + "availability": 0.997768, + "gen_feat_1": 512.31, + "gen_feat_2": 0.494924, + "gen_feat_3": 495.49 + } + }, + { + "id": "t_request_quote_gen_1", + "task_id": "t_request_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA POST /product/quote (Gen Shared)", + "features": { + "latency_ms": 122.37, + "cost_usd": 0.0, + "availability": 0.979755, + "gen_feat_1": 507.51, + "gen_feat_2": 0.493998, + "gen_feat_3": 513.92 + } + }, + { + "id": "t_get_quote_gen_1", + "task_id": "t_get_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA GET /quote (Gen Shared)", + "features": { + "latency_ms": 84.6, + "cost_usd": 0.0, + "availability": 0.999119, + "gen_feat_1": 499.61, + "gen_feat_2": 0.498885, + "gen_feat_3": 492.6 + } + }, + { + "id": "t_add_item_gen_1", + "task_id": "t_add_item", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/item (Gen Shared)", + "features": { + "latency_ms": 134.46, + "cost_usd": 0.0, + "availability": 0.987007, + "gen_feat_1": 499.47, + "gen_feat_2": 0.51104, + "gen_feat_3": 510.35 + } + }, + { + "id": "t_remove_item_gen_1", + "task_id": "t_remove_item", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order/item (Gen Shared)", + "features": { + "latency_ms": 84.0, + "cost_usd": 0.0, + "availability": 0.986162, + "gen_feat_1": 504.01, + "gen_feat_2": 0.48957, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_get_amount_gen_1", + "task_id": "t_get_amount", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/amount (Gen Shared)", + "features": { + "latency_ms": 56.45, + "cost_usd": 0.0, + "availability": 0.980217, + "gen_feat_1": 496.14, + "gen_feat_2": 0.50654, + "gen_feat_3": 490.74 + } + }, + { + "id": "t_checkout_gen_1", + "task_id": "t_checkout", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/payment (Gen Shared)", + "features": { + "latency_ms": 151.81, + "cost_usd": 0.0, + "availability": 0.994297, + "gen_feat_1": 498.47, + "gen_feat_2": 0.487221, + "gen_feat_3": 493.19 + } + }, + { + "id": "t_charge_payment_gen_1", + "task_id": "t_charge_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA POST /payment (Gen Shared)", + "features": { + "latency_ms": 313.81, + "cost_usd": 0.02, + "availability": 0.997468, + "gen_feat_1": 510.71, + "gen_feat_2": 0.511215, + "gen_feat_3": 498.76 + } + }, + { + "id": "t_list_confirmed_gen_1", + "task_id": "t_list_confirmed", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/confirmed (Gen Shared)", + "features": { + "latency_ms": 70.26, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.98, + "gen_feat_2": 0.510011, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_ship_order_gen_1", + "task_id": "t_ship_order", + "provider_id": "p_gen_shared", + "name": "ShopA fulfillment (Gen Shared)", + "features": { + "latency_ms": 469.4, + "cost_usd": 0.05, + "availability": 0.974618, + "gen_feat_1": 487.5, + "gen_feat_2": 0.512786, + "gen_feat_3": 513.89 + } + }, + { + "id": "t_update_shipment_gen_1", + "task_id": "t_update_shipment", + "provider_id": "p_gen_shared", + "name": "ShopA PUT /order/shipment (Gen Shared)", + "features": { + "latency_ms": 94.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 502.81, + "gen_feat_2": 0.50761, + "gen_feat_3": 507.89 + } + }, + { + "id": "t_cancel_order_gen_1", + "task_id": "t_cancel_order", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order (Gen Shared)", + "features": { + "latency_ms": 86.15, + "cost_usd": 0.0, + "availability": 0.993874, + "gen_feat_1": 498.93, + "gen_feat_2": 0.503401, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_refund_payment_gen_1", + "task_id": "t_refund_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA DELETE /payment (Gen Shared)", + "features": { + "latency_ms": 236.32, + "cost_usd": 0.02, + "availability": 0.993549, + "gen_feat_1": 487.89, + "gen_feat_2": 0.503178, + "gen_feat_3": 498.93 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_create_order", + "kind": "TASK", + "task_id": "t_create_order" + }, + { + "id": "n_edit_loop", + "kind": "LOOP", + "body": { + "id": "n_edit_action", + "kind": "XOR", + "branches": [ + { + "p": 0.7, + "child": { + "id": "n_add_item_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_request_quote", + "kind": "TASK", + "task_id": "t_request_quote" + }, + { + "id": "n_get_quote", + "kind": "TASK", + "task_id": "t_get_quote" + }, + { + "id": "n_add_item", + "kind": "TASK", + "task_id": "t_add_item" + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_remove_item", + "kind": "TASK", + "task_id": "t_remove_item" + } + }, + { + "p": 0.2, + "child": { + "id": "n_get_amount", + "kind": "TASK", + "task_id": "t_get_amount" + } + } + ] + }, + "expected_iterations": 3 + }, + { + "id": "n_decide_checkout_or_cancel", + "kind": "XOR", + "branches": [ + { + "p": 0.9, + "child": { + "id": "n_checkout_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_checkout", + "kind": "TASK", + "task_id": "t_checkout" + }, + { + "id": "n_charge_payment", + "kind": "TASK", + "task_id": "t_charge_payment" + }, + { + "id": "n_after_confirm", + "kind": "XOR", + "branches": [ + { + "p": 0.95, + "child": { + "id": "n_ship_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_list_confirmed", + "kind": "TASK", + "task_id": "t_list_confirmed" + }, + { + "id": "n_ship_order", + "kind": "TASK", + "task_id": "t_ship_order" + }, + { + "id": "n_update_shipment", + "kind": "TASK", + "task_id": "t_update_shipment" + } + ] + } + }, + { + "p": 0.05, + "child": { + "id": "n_cancel_confirmed_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_cancel_confirmed", + "kind": "TASK", + "task_id": "t_cancel_order" + }, + { + "id": "n_refund_payment", + "kind": "TASK", + "task_id": "t_refund_payment" + } + ] + } + } + ] + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_cancel_before_confirm", + "kind": "TASK", + "task_id": "t_cancel_order" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "bind_shop_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_create_order", + "t_add_item", + "t_remove_item", + "t_get_amount", + "t_checkout", + "t_list_confirmed", + "t_ship_order", + "t_update_shipment", + "t_cancel_order" + ] + }, + { + "id": "bind_catalog_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_request_quote", + "t_get_quote" + ] + }, + { + "id": "bind_payment_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_charge_payment", + "t_refund_payment" + ] + }, + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 2060.44, + "hard": true + }, + { + "id": "gen_c_local_t_add_item_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_add_item" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_add_item", + "t_cancel_order" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_add_item", + "t_charge_payment" + ], + "hard": true + } + ], + "objective": { + "type": "MANY", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/pautasso2009-restful-ecommerce_many_soft.json b/experimentation/instances/pautasso2009-restful-ecommerce_many_soft.json new file mode 100644 index 0000000..8a7ea4e --- /dev/null +++ b/experimentation/instances/pautasso2009-restful-ecommerce_many_soft.json @@ -0,0 +1,1086 @@ +{ + "metadata": { + "id": "pautasso2009-restful-ecommerce_many_soft", + "name": "RESTful e-Commerce scenario (Pautasso 2009) [many, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:05Z", + "description": "QoS-aware composition instance derived from the running e-Commerce example in Pautasso (2009) 'BPEL for REST'. QoS numbers are illustrative (the paper specifies the workflow/API but not QoS measurements).", + "paper": { + "title": "RESTful Web service composition with BPEL for REST", + "authors": "C. Pautasso", + "year": 2009, + "doi": "10.1016/j.datak.2009.02.016" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Invocation cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_shop_a", + "name": "Shop Service A" + }, + { + "id": "p_shop_b", + "name": "Shop Service B" + }, + { + "id": "p_catalog_a", + "name": "Catalog Service A" + }, + { + "id": "p_catalog_b", + "name": "Catalog Service B" + }, + { + "id": "p_payment_a", + "name": "Payment Service A" + }, + { + "id": "p_payment_b", + "name": "Payment Service B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_create_order", + "name": "Create order (POST /order)" + }, + { + "id": "t_request_quote", + "name": "Request quote (POST /product/quote)" + }, + { + "id": "t_get_quote", + "name": "Retrieve quote details (GET /quote)" + }, + { + "id": "t_add_item", + "name": "Add line item (POST /order/item)" + }, + { + "id": "t_remove_item", + "name": "Remove line item (DELETE /order/item)" + }, + { + "id": "t_get_amount", + "name": "Get order amount (GET /order/amount)" + }, + { + "id": "t_checkout", + "name": "Checkout (POST /order/payment)" + }, + { + "id": "t_charge_payment", + "name": "Charge payment (POST /payment)" + }, + { + "id": "t_list_confirmed", + "name": "List confirmed orders (GET /order/confirmed)" + }, + { + "id": "t_ship_order", + "name": "Ship order (fulfillment action within Shop binding)" + }, + { + "id": "t_update_shipment", + "name": "Update shipment info (PUT /order/shipment)" + }, + { + "id": "t_cancel_order", + "name": "Cancel order (DELETE /order)" + }, + { + "id": "t_refund_payment", + "name": "Refund payment (DELETE /payment)" + } + ], + "candidates": [ + { + "id": "c_shopA_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_a", + "name": "ShopA POST /order", + "features": { + "latency_ms": 105, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_b", + "name": "ShopB POST /order", + "features": { + "latency_ms": 130, + "cost_usd": 0.0004, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/item", + "features": { + "latency_ms": 135, + "cost_usd": 0.0008, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/item", + "features": { + "latency_ms": 160, + "cost_usd": 0.0006, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order/item", + "features": { + "latency_ms": 85, + "cost_usd": 0.0005, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order/item", + "features": { + "latency_ms": 100, + "cost_usd": 0.0003, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/amount", + "features": { + "latency_ms": 55, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/amount", + "features": { + "latency_ms": 75, + "cost_usd": 0.00018, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/payment", + "features": { + "latency_ms": 150, + "cost_usd": 0.0012, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/payment", + "features": { + "latency_ms": 185, + "cost_usd": 0.001, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/confirmed", + "features": { + "latency_ms": 70, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/confirmed", + "features": { + "latency_ms": 90, + "cost_usd": 0.0002, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_a", + "name": "ShopA fulfillment", + "features": { + "latency_ms": 480, + "cost_usd": 0.05, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_b", + "name": "ShopB fulfillment", + "features": { + "latency_ms": 520, + "cost_usd": 0.045, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_a", + "name": "ShopA PUT /order/shipment", + "features": { + "latency_ms": 95, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_b", + "name": "ShopB PUT /order/shipment", + "features": { + "latency_ms": 110, + "cost_usd": 0.00045, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order", + "features": { + "latency_ms": 85, + "cost_usd": 0.00035, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order", + "features": { + "latency_ms": 95, + "cost_usd": 0.00025, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA POST /product/quote", + "features": { + "latency_ms": 120, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB POST /product/quote", + "features": { + "latency_ms": 210, + "cost_usd": 0.0015, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA GET /quote", + "features": { + "latency_ms": 85, + "cost_usd": 0.001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB GET /quote", + "features": { + "latency_ms": 155, + "cost_usd": 0.0007, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_a", + "name": "PaymentA POST /payment", + "features": { + "latency_ms": 320, + "cost_usd": 0.02, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_b", + "name": "PaymentB POST /payment", + "features": { + "latency_ms": 380, + "cost_usd": 0.017, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_a", + "name": "PaymentA DELETE /payment", + "features": { + "latency_ms": 240, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_b", + "name": "PaymentB DELETE /payment", + "features": { + "latency_ms": 290, + "cost_usd": 0.013, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_create_order_gen_1", + "task_id": "t_create_order", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order (Gen Shared)", + "features": { + "latency_ms": 105.45, + "cost_usd": 0.0, + "availability": 0.997768, + "gen_feat_1": 512.31, + "gen_feat_2": 0.494924, + "gen_feat_3": 495.49 + } + }, + { + "id": "t_request_quote_gen_1", + "task_id": "t_request_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA POST /product/quote (Gen Shared)", + "features": { + "latency_ms": 122.37, + "cost_usd": 0.0, + "availability": 0.979755, + "gen_feat_1": 507.51, + "gen_feat_2": 0.493998, + "gen_feat_3": 513.92 + } + }, + { + "id": "t_get_quote_gen_1", + "task_id": "t_get_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA GET /quote (Gen Shared)", + "features": { + "latency_ms": 84.6, + "cost_usd": 0.0, + "availability": 0.999119, + "gen_feat_1": 499.61, + "gen_feat_2": 0.498885, + "gen_feat_3": 492.6 + } + }, + { + "id": "t_add_item_gen_1", + "task_id": "t_add_item", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/item (Gen Shared)", + "features": { + "latency_ms": 134.46, + "cost_usd": 0.0, + "availability": 0.987007, + "gen_feat_1": 499.47, + "gen_feat_2": 0.51104, + "gen_feat_3": 510.35 + } + }, + { + "id": "t_remove_item_gen_1", + "task_id": "t_remove_item", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order/item (Gen Shared)", + "features": { + "latency_ms": 84.0, + "cost_usd": 0.0, + "availability": 0.986162, + "gen_feat_1": 504.01, + "gen_feat_2": 0.48957, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_get_amount_gen_1", + "task_id": "t_get_amount", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/amount (Gen Shared)", + "features": { + "latency_ms": 56.45, + "cost_usd": 0.0, + "availability": 0.980217, + "gen_feat_1": 496.14, + "gen_feat_2": 0.50654, + "gen_feat_3": 490.74 + } + }, + { + "id": "t_checkout_gen_1", + "task_id": "t_checkout", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/payment (Gen Shared)", + "features": { + "latency_ms": 151.81, + "cost_usd": 0.0, + "availability": 0.994297, + "gen_feat_1": 498.47, + "gen_feat_2": 0.487221, + "gen_feat_3": 493.19 + } + }, + { + "id": "t_charge_payment_gen_1", + "task_id": "t_charge_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA POST /payment (Gen Shared)", + "features": { + "latency_ms": 313.81, + "cost_usd": 0.02, + "availability": 0.997468, + "gen_feat_1": 510.71, + "gen_feat_2": 0.511215, + "gen_feat_3": 498.76 + } + }, + { + "id": "t_list_confirmed_gen_1", + "task_id": "t_list_confirmed", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/confirmed (Gen Shared)", + "features": { + "latency_ms": 70.26, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.98, + "gen_feat_2": 0.510011, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_ship_order_gen_1", + "task_id": "t_ship_order", + "provider_id": "p_gen_shared", + "name": "ShopA fulfillment (Gen Shared)", + "features": { + "latency_ms": 469.4, + "cost_usd": 0.05, + "availability": 0.974618, + "gen_feat_1": 487.5, + "gen_feat_2": 0.512786, + "gen_feat_3": 513.89 + } + }, + { + "id": "t_update_shipment_gen_1", + "task_id": "t_update_shipment", + "provider_id": "p_gen_shared", + "name": "ShopA PUT /order/shipment (Gen Shared)", + "features": { + "latency_ms": 94.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 502.81, + "gen_feat_2": 0.50761, + "gen_feat_3": 507.89 + } + }, + { + "id": "t_cancel_order_gen_1", + "task_id": "t_cancel_order", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order (Gen Shared)", + "features": { + "latency_ms": 86.15, + "cost_usd": 0.0, + "availability": 0.993874, + "gen_feat_1": 498.93, + "gen_feat_2": 0.503401, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_refund_payment_gen_1", + "task_id": "t_refund_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA DELETE /payment (Gen Shared)", + "features": { + "latency_ms": 236.32, + "cost_usd": 0.02, + "availability": 0.993549, + "gen_feat_1": 487.89, + "gen_feat_2": 0.503178, + "gen_feat_3": 498.93 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_create_order", + "kind": "TASK", + "task_id": "t_create_order" + }, + { + "id": "n_edit_loop", + "kind": "LOOP", + "body": { + "id": "n_edit_action", + "kind": "XOR", + "branches": [ + { + "p": 0.7, + "child": { + "id": "n_add_item_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_request_quote", + "kind": "TASK", + "task_id": "t_request_quote" + }, + { + "id": "n_get_quote", + "kind": "TASK", + "task_id": "t_get_quote" + }, + { + "id": "n_add_item", + "kind": "TASK", + "task_id": "t_add_item" + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_remove_item", + "kind": "TASK", + "task_id": "t_remove_item" + } + }, + { + "p": 0.2, + "child": { + "id": "n_get_amount", + "kind": "TASK", + "task_id": "t_get_amount" + } + } + ] + }, + "expected_iterations": 3 + }, + { + "id": "n_decide_checkout_or_cancel", + "kind": "XOR", + "branches": [ + { + "p": 0.9, + "child": { + "id": "n_checkout_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_checkout", + "kind": "TASK", + "task_id": "t_checkout" + }, + { + "id": "n_charge_payment", + "kind": "TASK", + "task_id": "t_charge_payment" + }, + { + "id": "n_after_confirm", + "kind": "XOR", + "branches": [ + { + "p": 0.95, + "child": { + "id": "n_ship_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_list_confirmed", + "kind": "TASK", + "task_id": "t_list_confirmed" + }, + { + "id": "n_ship_order", + "kind": "TASK", + "task_id": "t_ship_order" + }, + { + "id": "n_update_shipment", + "kind": "TASK", + "task_id": "t_update_shipment" + } + ] + } + }, + { + "p": 0.05, + "child": { + "id": "n_cancel_confirmed_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_cancel_confirmed", + "kind": "TASK", + "task_id": "t_cancel_order" + }, + { + "id": "n_refund_payment", + "kind": "TASK", + "task_id": "t_refund_payment" + } + ] + } + } + ] + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_cancel_before_confirm", + "kind": "TASK", + "task_id": "t_cancel_order" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "bind_shop_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_create_order", + "t_add_item", + "t_remove_item", + "t_get_amount", + "t_checkout", + "t_list_confirmed", + "t_ship_order", + "t_update_shipment", + "t_cancel_order" + ], + "hard": false + }, + { + "id": "bind_catalog_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_request_quote", + "t_get_quote" + ], + "hard": false + }, + { + "id": "bind_payment_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_charge_payment", + "t_refund_payment" + ], + "hard": false + }, + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 2060.44, + "hard": false + }, + { + "id": "gen_c_local_t_add_item_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_add_item" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_add_item", + "t_cancel_order" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_add_item", + "t_charge_payment" + ], + "hard": false + } + ], + "objective": { + "type": "MANY", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/pautasso2009-restful-ecommerce_mono_one_hard.json b/experimentation/instances/pautasso2009-restful-ecommerce_mono_one_hard.json new file mode 100644 index 0000000..c367867 --- /dev/null +++ b/experimentation/instances/pautasso2009-restful-ecommerce_mono_one_hard.json @@ -0,0 +1,1073 @@ +{ + "metadata": { + "id": "pautasso2009-restful-ecommerce_mono_one_hard", + "name": "RESTful e-Commerce scenario (Pautasso 2009) [mono_one, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:57Z", + "description": "QoS-aware composition instance derived from the running e-Commerce example in Pautasso (2009) 'BPEL for REST'. QoS numbers are illustrative (the paper specifies the workflow/API but not QoS measurements).", + "paper": { + "title": "RESTful Web service composition with BPEL for REST", + "authors": "C. Pautasso", + "year": 2009, + "doi": "10.1016/j.datak.2009.02.016" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Invocation cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_shop_a", + "name": "Shop Service A" + }, + { + "id": "p_shop_b", + "name": "Shop Service B" + }, + { + "id": "p_catalog_a", + "name": "Catalog Service A" + }, + { + "id": "p_catalog_b", + "name": "Catalog Service B" + }, + { + "id": "p_payment_a", + "name": "Payment Service A" + }, + { + "id": "p_payment_b", + "name": "Payment Service B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_create_order", + "name": "Create order (POST /order)" + }, + { + "id": "t_request_quote", + "name": "Request quote (POST /product/quote)" + }, + { + "id": "t_get_quote", + "name": "Retrieve quote details (GET /quote)" + }, + { + "id": "t_add_item", + "name": "Add line item (POST /order/item)" + }, + { + "id": "t_remove_item", + "name": "Remove line item (DELETE /order/item)" + }, + { + "id": "t_get_amount", + "name": "Get order amount (GET /order/amount)" + }, + { + "id": "t_checkout", + "name": "Checkout (POST /order/payment)" + }, + { + "id": "t_charge_payment", + "name": "Charge payment (POST /payment)" + }, + { + "id": "t_list_confirmed", + "name": "List confirmed orders (GET /order/confirmed)" + }, + { + "id": "t_ship_order", + "name": "Ship order (fulfillment action within Shop binding)" + }, + { + "id": "t_update_shipment", + "name": "Update shipment info (PUT /order/shipment)" + }, + { + "id": "t_cancel_order", + "name": "Cancel order (DELETE /order)" + }, + { + "id": "t_refund_payment", + "name": "Refund payment (DELETE /payment)" + } + ], + "candidates": [ + { + "id": "c_shopA_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_a", + "name": "ShopA POST /order", + "features": { + "latency_ms": 105, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_b", + "name": "ShopB POST /order", + "features": { + "latency_ms": 130, + "cost_usd": 0.0004, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/item", + "features": { + "latency_ms": 135, + "cost_usd": 0.0008, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/item", + "features": { + "latency_ms": 160, + "cost_usd": 0.0006, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order/item", + "features": { + "latency_ms": 85, + "cost_usd": 0.0005, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order/item", + "features": { + "latency_ms": 100, + "cost_usd": 0.0003, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/amount", + "features": { + "latency_ms": 55, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/amount", + "features": { + "latency_ms": 75, + "cost_usd": 0.00018, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/payment", + "features": { + "latency_ms": 150, + "cost_usd": 0.0012, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/payment", + "features": { + "latency_ms": 185, + "cost_usd": 0.001, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/confirmed", + "features": { + "latency_ms": 70, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/confirmed", + "features": { + "latency_ms": 90, + "cost_usd": 0.0002, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_a", + "name": "ShopA fulfillment", + "features": { + "latency_ms": 480, + "cost_usd": 0.05, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_b", + "name": "ShopB fulfillment", + "features": { + "latency_ms": 520, + "cost_usd": 0.045, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_a", + "name": "ShopA PUT /order/shipment", + "features": { + "latency_ms": 95, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_b", + "name": "ShopB PUT /order/shipment", + "features": { + "latency_ms": 110, + "cost_usd": 0.00045, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order", + "features": { + "latency_ms": 85, + "cost_usd": 0.00035, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order", + "features": { + "latency_ms": 95, + "cost_usd": 0.00025, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA POST /product/quote", + "features": { + "latency_ms": 120, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB POST /product/quote", + "features": { + "latency_ms": 210, + "cost_usd": 0.0015, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA GET /quote", + "features": { + "latency_ms": 85, + "cost_usd": 0.001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB GET /quote", + "features": { + "latency_ms": 155, + "cost_usd": 0.0007, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_a", + "name": "PaymentA POST /payment", + "features": { + "latency_ms": 320, + "cost_usd": 0.02, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_b", + "name": "PaymentB POST /payment", + "features": { + "latency_ms": 380, + "cost_usd": 0.017, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_a", + "name": "PaymentA DELETE /payment", + "features": { + "latency_ms": 240, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_b", + "name": "PaymentB DELETE /payment", + "features": { + "latency_ms": 290, + "cost_usd": 0.013, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_create_order_gen_1", + "task_id": "t_create_order", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order (Gen Shared)", + "features": { + "latency_ms": 105.45, + "cost_usd": 0.0, + "availability": 0.997768, + "gen_feat_1": 512.31, + "gen_feat_2": 0.494924, + "gen_feat_3": 495.49 + } + }, + { + "id": "t_request_quote_gen_1", + "task_id": "t_request_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA POST /product/quote (Gen Shared)", + "features": { + "latency_ms": 122.37, + "cost_usd": 0.0, + "availability": 0.979755, + "gen_feat_1": 507.51, + "gen_feat_2": 0.493998, + "gen_feat_3": 513.92 + } + }, + { + "id": "t_get_quote_gen_1", + "task_id": "t_get_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA GET /quote (Gen Shared)", + "features": { + "latency_ms": 84.6, + "cost_usd": 0.0, + "availability": 0.999119, + "gen_feat_1": 499.61, + "gen_feat_2": 0.498885, + "gen_feat_3": 492.6 + } + }, + { + "id": "t_add_item_gen_1", + "task_id": "t_add_item", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/item (Gen Shared)", + "features": { + "latency_ms": 134.46, + "cost_usd": 0.0, + "availability": 0.987007, + "gen_feat_1": 499.47, + "gen_feat_2": 0.51104, + "gen_feat_3": 510.35 + } + }, + { + "id": "t_remove_item_gen_1", + "task_id": "t_remove_item", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order/item (Gen Shared)", + "features": { + "latency_ms": 84.0, + "cost_usd": 0.0, + "availability": 0.986162, + "gen_feat_1": 504.01, + "gen_feat_2": 0.48957, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_get_amount_gen_1", + "task_id": "t_get_amount", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/amount (Gen Shared)", + "features": { + "latency_ms": 56.45, + "cost_usd": 0.0, + "availability": 0.980217, + "gen_feat_1": 496.14, + "gen_feat_2": 0.50654, + "gen_feat_3": 490.74 + } + }, + { + "id": "t_checkout_gen_1", + "task_id": "t_checkout", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/payment (Gen Shared)", + "features": { + "latency_ms": 151.81, + "cost_usd": 0.0, + "availability": 0.994297, + "gen_feat_1": 498.47, + "gen_feat_2": 0.487221, + "gen_feat_3": 493.19 + } + }, + { + "id": "t_charge_payment_gen_1", + "task_id": "t_charge_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA POST /payment (Gen Shared)", + "features": { + "latency_ms": 313.81, + "cost_usd": 0.02, + "availability": 0.997468, + "gen_feat_1": 510.71, + "gen_feat_2": 0.511215, + "gen_feat_3": 498.76 + } + }, + { + "id": "t_list_confirmed_gen_1", + "task_id": "t_list_confirmed", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/confirmed (Gen Shared)", + "features": { + "latency_ms": 70.26, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.98, + "gen_feat_2": 0.510011, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_ship_order_gen_1", + "task_id": "t_ship_order", + "provider_id": "p_gen_shared", + "name": "ShopA fulfillment (Gen Shared)", + "features": { + "latency_ms": 469.4, + "cost_usd": 0.05, + "availability": 0.974618, + "gen_feat_1": 487.5, + "gen_feat_2": 0.512786, + "gen_feat_3": 513.89 + } + }, + { + "id": "t_update_shipment_gen_1", + "task_id": "t_update_shipment", + "provider_id": "p_gen_shared", + "name": "ShopA PUT /order/shipment (Gen Shared)", + "features": { + "latency_ms": 94.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 502.81, + "gen_feat_2": 0.50761, + "gen_feat_3": 507.89 + } + }, + { + "id": "t_cancel_order_gen_1", + "task_id": "t_cancel_order", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order (Gen Shared)", + "features": { + "latency_ms": 86.15, + "cost_usd": 0.0, + "availability": 0.993874, + "gen_feat_1": 498.93, + "gen_feat_2": 0.503401, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_refund_payment_gen_1", + "task_id": "t_refund_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA DELETE /payment (Gen Shared)", + "features": { + "latency_ms": 236.32, + "cost_usd": 0.02, + "availability": 0.993549, + "gen_feat_1": 487.89, + "gen_feat_2": 0.503178, + "gen_feat_3": 498.93 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_create_order", + "kind": "TASK", + "task_id": "t_create_order" + }, + { + "id": "n_edit_loop", + "kind": "LOOP", + "body": { + "id": "n_edit_action", + "kind": "XOR", + "branches": [ + { + "p": 0.7, + "child": { + "id": "n_add_item_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_request_quote", + "kind": "TASK", + "task_id": "t_request_quote" + }, + { + "id": "n_get_quote", + "kind": "TASK", + "task_id": "t_get_quote" + }, + { + "id": "n_add_item", + "kind": "TASK", + "task_id": "t_add_item" + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_remove_item", + "kind": "TASK", + "task_id": "t_remove_item" + } + }, + { + "p": 0.2, + "child": { + "id": "n_get_amount", + "kind": "TASK", + "task_id": "t_get_amount" + } + } + ] + }, + "expected_iterations": 3 + }, + { + "id": "n_decide_checkout_or_cancel", + "kind": "XOR", + "branches": [ + { + "p": 0.9, + "child": { + "id": "n_checkout_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_checkout", + "kind": "TASK", + "task_id": "t_checkout" + }, + { + "id": "n_charge_payment", + "kind": "TASK", + "task_id": "t_charge_payment" + }, + { + "id": "n_after_confirm", + "kind": "XOR", + "branches": [ + { + "p": 0.95, + "child": { + "id": "n_ship_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_list_confirmed", + "kind": "TASK", + "task_id": "t_list_confirmed" + }, + { + "id": "n_ship_order", + "kind": "TASK", + "task_id": "t_ship_order" + }, + { + "id": "n_update_shipment", + "kind": "TASK", + "task_id": "t_update_shipment" + } + ] + } + }, + { + "p": 0.05, + "child": { + "id": "n_cancel_confirmed_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_cancel_confirmed", + "kind": "TASK", + "task_id": "t_cancel_order" + }, + { + "id": "n_refund_payment", + "kind": "TASK", + "task_id": "t_refund_payment" + } + ] + } + } + ] + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_cancel_before_confirm", + "kind": "TASK", + "task_id": "t_cancel_order" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "bind_shop_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_create_order", + "t_add_item", + "t_remove_item", + "t_get_amount", + "t_checkout", + "t_list_confirmed", + "t_ship_order", + "t_update_shipment", + "t_cancel_order" + ] + }, + { + "id": "bind_catalog_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_request_quote", + "t_get_quote" + ] + }, + { + "id": "bind_payment_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_charge_payment", + "t_refund_payment" + ] + }, + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1866.14, + "hard": true + }, + { + "id": "gen_c_local_t_add_item_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_add_item" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_add_item", + "t_cancel_order" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_add_item", + "t_refund_payment" + ], + "hard": true + } + ], + "objective": { + "type": "MONO", + "targets": [ + "availability" + ], + "weights": { + "availability": 1.0 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/pautasso2009-restful-ecommerce_mono_one_soft.json b/experimentation/instances/pautasso2009-restful-ecommerce_mono_one_soft.json new file mode 100644 index 0000000..455763d --- /dev/null +++ b/experimentation/instances/pautasso2009-restful-ecommerce_mono_one_soft.json @@ -0,0 +1,1076 @@ +{ + "metadata": { + "id": "pautasso2009-restful-ecommerce_mono_one_soft", + "name": "RESTful e-Commerce scenario (Pautasso 2009) [mono_one, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:34:59Z", + "description": "QoS-aware composition instance derived from the running e-Commerce example in Pautasso (2009) 'BPEL for REST'. QoS numbers are illustrative (the paper specifies the workflow/API but not QoS measurements).", + "paper": { + "title": "RESTful Web service composition with BPEL for REST", + "authors": "C. Pautasso", + "year": 2009, + "doi": "10.1016/j.datak.2009.02.016" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Invocation cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_shop_a", + "name": "Shop Service A" + }, + { + "id": "p_shop_b", + "name": "Shop Service B" + }, + { + "id": "p_catalog_a", + "name": "Catalog Service A" + }, + { + "id": "p_catalog_b", + "name": "Catalog Service B" + }, + { + "id": "p_payment_a", + "name": "Payment Service A" + }, + { + "id": "p_payment_b", + "name": "Payment Service B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_create_order", + "name": "Create order (POST /order)" + }, + { + "id": "t_request_quote", + "name": "Request quote (POST /product/quote)" + }, + { + "id": "t_get_quote", + "name": "Retrieve quote details (GET /quote)" + }, + { + "id": "t_add_item", + "name": "Add line item (POST /order/item)" + }, + { + "id": "t_remove_item", + "name": "Remove line item (DELETE /order/item)" + }, + { + "id": "t_get_amount", + "name": "Get order amount (GET /order/amount)" + }, + { + "id": "t_checkout", + "name": "Checkout (POST /order/payment)" + }, + { + "id": "t_charge_payment", + "name": "Charge payment (POST /payment)" + }, + { + "id": "t_list_confirmed", + "name": "List confirmed orders (GET /order/confirmed)" + }, + { + "id": "t_ship_order", + "name": "Ship order (fulfillment action within Shop binding)" + }, + { + "id": "t_update_shipment", + "name": "Update shipment info (PUT /order/shipment)" + }, + { + "id": "t_cancel_order", + "name": "Cancel order (DELETE /order)" + }, + { + "id": "t_refund_payment", + "name": "Refund payment (DELETE /payment)" + } + ], + "candidates": [ + { + "id": "c_shopA_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_a", + "name": "ShopA POST /order", + "features": { + "latency_ms": 105, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_b", + "name": "ShopB POST /order", + "features": { + "latency_ms": 130, + "cost_usd": 0.0004, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/item", + "features": { + "latency_ms": 135, + "cost_usd": 0.0008, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/item", + "features": { + "latency_ms": 160, + "cost_usd": 0.0006, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order/item", + "features": { + "latency_ms": 85, + "cost_usd": 0.0005, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order/item", + "features": { + "latency_ms": 100, + "cost_usd": 0.0003, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/amount", + "features": { + "latency_ms": 55, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/amount", + "features": { + "latency_ms": 75, + "cost_usd": 0.00018, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/payment", + "features": { + "latency_ms": 150, + "cost_usd": 0.0012, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/payment", + "features": { + "latency_ms": 185, + "cost_usd": 0.001, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/confirmed", + "features": { + "latency_ms": 70, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/confirmed", + "features": { + "latency_ms": 90, + "cost_usd": 0.0002, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_a", + "name": "ShopA fulfillment", + "features": { + "latency_ms": 480, + "cost_usd": 0.05, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_b", + "name": "ShopB fulfillment", + "features": { + "latency_ms": 520, + "cost_usd": 0.045, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_a", + "name": "ShopA PUT /order/shipment", + "features": { + "latency_ms": 95, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_b", + "name": "ShopB PUT /order/shipment", + "features": { + "latency_ms": 110, + "cost_usd": 0.00045, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order", + "features": { + "latency_ms": 85, + "cost_usd": 0.00035, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order", + "features": { + "latency_ms": 95, + "cost_usd": 0.00025, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA POST /product/quote", + "features": { + "latency_ms": 120, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB POST /product/quote", + "features": { + "latency_ms": 210, + "cost_usd": 0.0015, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA GET /quote", + "features": { + "latency_ms": 85, + "cost_usd": 0.001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB GET /quote", + "features": { + "latency_ms": 155, + "cost_usd": 0.0007, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_a", + "name": "PaymentA POST /payment", + "features": { + "latency_ms": 320, + "cost_usd": 0.02, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_b", + "name": "PaymentB POST /payment", + "features": { + "latency_ms": 380, + "cost_usd": 0.017, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_a", + "name": "PaymentA DELETE /payment", + "features": { + "latency_ms": 240, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_b", + "name": "PaymentB DELETE /payment", + "features": { + "latency_ms": 290, + "cost_usd": 0.013, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_create_order_gen_1", + "task_id": "t_create_order", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order (Gen Shared)", + "features": { + "latency_ms": 105.45, + "cost_usd": 0.0, + "availability": 0.997768, + "gen_feat_1": 512.31, + "gen_feat_2": 0.494924, + "gen_feat_3": 495.49 + } + }, + { + "id": "t_request_quote_gen_1", + "task_id": "t_request_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA POST /product/quote (Gen Shared)", + "features": { + "latency_ms": 122.37, + "cost_usd": 0.0, + "availability": 0.979755, + "gen_feat_1": 507.51, + "gen_feat_2": 0.493998, + "gen_feat_3": 513.92 + } + }, + { + "id": "t_get_quote_gen_1", + "task_id": "t_get_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA GET /quote (Gen Shared)", + "features": { + "latency_ms": 84.6, + "cost_usd": 0.0, + "availability": 0.999119, + "gen_feat_1": 499.61, + "gen_feat_2": 0.498885, + "gen_feat_3": 492.6 + } + }, + { + "id": "t_add_item_gen_1", + "task_id": "t_add_item", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/item (Gen Shared)", + "features": { + "latency_ms": 134.46, + "cost_usd": 0.0, + "availability": 0.987007, + "gen_feat_1": 499.47, + "gen_feat_2": 0.51104, + "gen_feat_3": 510.35 + } + }, + { + "id": "t_remove_item_gen_1", + "task_id": "t_remove_item", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order/item (Gen Shared)", + "features": { + "latency_ms": 84.0, + "cost_usd": 0.0, + "availability": 0.986162, + "gen_feat_1": 504.01, + "gen_feat_2": 0.48957, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_get_amount_gen_1", + "task_id": "t_get_amount", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/amount (Gen Shared)", + "features": { + "latency_ms": 56.45, + "cost_usd": 0.0, + "availability": 0.980217, + "gen_feat_1": 496.14, + "gen_feat_2": 0.50654, + "gen_feat_3": 490.74 + } + }, + { + "id": "t_checkout_gen_1", + "task_id": "t_checkout", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/payment (Gen Shared)", + "features": { + "latency_ms": 151.81, + "cost_usd": 0.0, + "availability": 0.994297, + "gen_feat_1": 498.47, + "gen_feat_2": 0.487221, + "gen_feat_3": 493.19 + } + }, + { + "id": "t_charge_payment_gen_1", + "task_id": "t_charge_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA POST /payment (Gen Shared)", + "features": { + "latency_ms": 313.81, + "cost_usd": 0.02, + "availability": 0.997468, + "gen_feat_1": 510.71, + "gen_feat_2": 0.511215, + "gen_feat_3": 498.76 + } + }, + { + "id": "t_list_confirmed_gen_1", + "task_id": "t_list_confirmed", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/confirmed (Gen Shared)", + "features": { + "latency_ms": 70.26, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.98, + "gen_feat_2": 0.510011, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_ship_order_gen_1", + "task_id": "t_ship_order", + "provider_id": "p_gen_shared", + "name": "ShopA fulfillment (Gen Shared)", + "features": { + "latency_ms": 469.4, + "cost_usd": 0.05, + "availability": 0.974618, + "gen_feat_1": 487.5, + "gen_feat_2": 0.512786, + "gen_feat_3": 513.89 + } + }, + { + "id": "t_update_shipment_gen_1", + "task_id": "t_update_shipment", + "provider_id": "p_gen_shared", + "name": "ShopA PUT /order/shipment (Gen Shared)", + "features": { + "latency_ms": 94.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 502.81, + "gen_feat_2": 0.50761, + "gen_feat_3": 507.89 + } + }, + { + "id": "t_cancel_order_gen_1", + "task_id": "t_cancel_order", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order (Gen Shared)", + "features": { + "latency_ms": 86.15, + "cost_usd": 0.0, + "availability": 0.993874, + "gen_feat_1": 498.93, + "gen_feat_2": 0.503401, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_refund_payment_gen_1", + "task_id": "t_refund_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA DELETE /payment (Gen Shared)", + "features": { + "latency_ms": 236.32, + "cost_usd": 0.02, + "availability": 0.993549, + "gen_feat_1": 487.89, + "gen_feat_2": 0.503178, + "gen_feat_3": 498.93 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_create_order", + "kind": "TASK", + "task_id": "t_create_order" + }, + { + "id": "n_edit_loop", + "kind": "LOOP", + "body": { + "id": "n_edit_action", + "kind": "XOR", + "branches": [ + { + "p": 0.7, + "child": { + "id": "n_add_item_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_request_quote", + "kind": "TASK", + "task_id": "t_request_quote" + }, + { + "id": "n_get_quote", + "kind": "TASK", + "task_id": "t_get_quote" + }, + { + "id": "n_add_item", + "kind": "TASK", + "task_id": "t_add_item" + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_remove_item", + "kind": "TASK", + "task_id": "t_remove_item" + } + }, + { + "p": 0.2, + "child": { + "id": "n_get_amount", + "kind": "TASK", + "task_id": "t_get_amount" + } + } + ] + }, + "expected_iterations": 3 + }, + { + "id": "n_decide_checkout_or_cancel", + "kind": "XOR", + "branches": [ + { + "p": 0.9, + "child": { + "id": "n_checkout_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_checkout", + "kind": "TASK", + "task_id": "t_checkout" + }, + { + "id": "n_charge_payment", + "kind": "TASK", + "task_id": "t_charge_payment" + }, + { + "id": "n_after_confirm", + "kind": "XOR", + "branches": [ + { + "p": 0.95, + "child": { + "id": "n_ship_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_list_confirmed", + "kind": "TASK", + "task_id": "t_list_confirmed" + }, + { + "id": "n_ship_order", + "kind": "TASK", + "task_id": "t_ship_order" + }, + { + "id": "n_update_shipment", + "kind": "TASK", + "task_id": "t_update_shipment" + } + ] + } + }, + { + "p": 0.05, + "child": { + "id": "n_cancel_confirmed_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_cancel_confirmed", + "kind": "TASK", + "task_id": "t_cancel_order" + }, + { + "id": "n_refund_payment", + "kind": "TASK", + "task_id": "t_refund_payment" + } + ] + } + } + ] + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_cancel_before_confirm", + "kind": "TASK", + "task_id": "t_cancel_order" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "bind_shop_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_create_order", + "t_add_item", + "t_remove_item", + "t_get_amount", + "t_checkout", + "t_list_confirmed", + "t_ship_order", + "t_update_shipment", + "t_cancel_order" + ], + "hard": false + }, + { + "id": "bind_catalog_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_request_quote", + "t_get_quote" + ], + "hard": false + }, + { + "id": "bind_payment_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_charge_payment", + "t_refund_payment" + ], + "hard": false + }, + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1866.14, + "hard": false + }, + { + "id": "gen_c_local_t_add_item_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_add_item" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_add_item", + "t_cancel_order" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_add_item", + "t_refund_payment" + ], + "hard": false + } + ], + "objective": { + "type": "MONO", + "targets": [ + "availability" + ], + "weights": { + "availability": 1.0 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/pautasso2009-restful-ecommerce_mono_utility_hard.json b/experimentation/instances/pautasso2009-restful-ecommerce_mono_utility_hard.json new file mode 100644 index 0000000..fc27c90 --- /dev/null +++ b/experimentation/instances/pautasso2009-restful-ecommerce_mono_utility_hard.json @@ -0,0 +1,1083 @@ +{ + "metadata": { + "id": "pautasso2009-restful-ecommerce_mono_utility_hard", + "name": "RESTful e-Commerce scenario (Pautasso 2009) [mono_utility, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:00Z", + "description": "QoS-aware composition instance derived from the running e-Commerce example in Pautasso (2009) 'BPEL for REST'. QoS numbers are illustrative (the paper specifies the workflow/API but not QoS measurements).", + "paper": { + "title": "RESTful Web service composition with BPEL for REST", + "authors": "C. Pautasso", + "year": 2009, + "doi": "10.1016/j.datak.2009.02.016" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Invocation cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_shop_a", + "name": "Shop Service A" + }, + { + "id": "p_shop_b", + "name": "Shop Service B" + }, + { + "id": "p_catalog_a", + "name": "Catalog Service A" + }, + { + "id": "p_catalog_b", + "name": "Catalog Service B" + }, + { + "id": "p_payment_a", + "name": "Payment Service A" + }, + { + "id": "p_payment_b", + "name": "Payment Service B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_create_order", + "name": "Create order (POST /order)" + }, + { + "id": "t_request_quote", + "name": "Request quote (POST /product/quote)" + }, + { + "id": "t_get_quote", + "name": "Retrieve quote details (GET /quote)" + }, + { + "id": "t_add_item", + "name": "Add line item (POST /order/item)" + }, + { + "id": "t_remove_item", + "name": "Remove line item (DELETE /order/item)" + }, + { + "id": "t_get_amount", + "name": "Get order amount (GET /order/amount)" + }, + { + "id": "t_checkout", + "name": "Checkout (POST /order/payment)" + }, + { + "id": "t_charge_payment", + "name": "Charge payment (POST /payment)" + }, + { + "id": "t_list_confirmed", + "name": "List confirmed orders (GET /order/confirmed)" + }, + { + "id": "t_ship_order", + "name": "Ship order (fulfillment action within Shop binding)" + }, + { + "id": "t_update_shipment", + "name": "Update shipment info (PUT /order/shipment)" + }, + { + "id": "t_cancel_order", + "name": "Cancel order (DELETE /order)" + }, + { + "id": "t_refund_payment", + "name": "Refund payment (DELETE /payment)" + } + ], + "candidates": [ + { + "id": "c_shopA_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_a", + "name": "ShopA POST /order", + "features": { + "latency_ms": 105, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_b", + "name": "ShopB POST /order", + "features": { + "latency_ms": 130, + "cost_usd": 0.0004, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/item", + "features": { + "latency_ms": 135, + "cost_usd": 0.0008, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/item", + "features": { + "latency_ms": 160, + "cost_usd": 0.0006, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order/item", + "features": { + "latency_ms": 85, + "cost_usd": 0.0005, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order/item", + "features": { + "latency_ms": 100, + "cost_usd": 0.0003, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/amount", + "features": { + "latency_ms": 55, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/amount", + "features": { + "latency_ms": 75, + "cost_usd": 0.00018, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/payment", + "features": { + "latency_ms": 150, + "cost_usd": 0.0012, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/payment", + "features": { + "latency_ms": 185, + "cost_usd": 0.001, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/confirmed", + "features": { + "latency_ms": 70, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/confirmed", + "features": { + "latency_ms": 90, + "cost_usd": 0.0002, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_a", + "name": "ShopA fulfillment", + "features": { + "latency_ms": 480, + "cost_usd": 0.05, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_b", + "name": "ShopB fulfillment", + "features": { + "latency_ms": 520, + "cost_usd": 0.045, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_a", + "name": "ShopA PUT /order/shipment", + "features": { + "latency_ms": 95, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_b", + "name": "ShopB PUT /order/shipment", + "features": { + "latency_ms": 110, + "cost_usd": 0.00045, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order", + "features": { + "latency_ms": 85, + "cost_usd": 0.00035, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order", + "features": { + "latency_ms": 95, + "cost_usd": 0.00025, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA POST /product/quote", + "features": { + "latency_ms": 120, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB POST /product/quote", + "features": { + "latency_ms": 210, + "cost_usd": 0.0015, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA GET /quote", + "features": { + "latency_ms": 85, + "cost_usd": 0.001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB GET /quote", + "features": { + "latency_ms": 155, + "cost_usd": 0.0007, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_a", + "name": "PaymentA POST /payment", + "features": { + "latency_ms": 320, + "cost_usd": 0.02, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_b", + "name": "PaymentB POST /payment", + "features": { + "latency_ms": 380, + "cost_usd": 0.017, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_a", + "name": "PaymentA DELETE /payment", + "features": { + "latency_ms": 240, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_b", + "name": "PaymentB DELETE /payment", + "features": { + "latency_ms": 290, + "cost_usd": 0.013, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_create_order_gen_1", + "task_id": "t_create_order", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order (Gen Shared)", + "features": { + "latency_ms": 105.45, + "cost_usd": 0.0, + "availability": 0.997768, + "gen_feat_1": 512.31, + "gen_feat_2": 0.494924, + "gen_feat_3": 495.49 + } + }, + { + "id": "t_request_quote_gen_1", + "task_id": "t_request_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA POST /product/quote (Gen Shared)", + "features": { + "latency_ms": 122.37, + "cost_usd": 0.0, + "availability": 0.979755, + "gen_feat_1": 507.51, + "gen_feat_2": 0.493998, + "gen_feat_3": 513.92 + } + }, + { + "id": "t_get_quote_gen_1", + "task_id": "t_get_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA GET /quote (Gen Shared)", + "features": { + "latency_ms": 84.6, + "cost_usd": 0.0, + "availability": 0.999119, + "gen_feat_1": 499.61, + "gen_feat_2": 0.498885, + "gen_feat_3": 492.6 + } + }, + { + "id": "t_add_item_gen_1", + "task_id": "t_add_item", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/item (Gen Shared)", + "features": { + "latency_ms": 134.46, + "cost_usd": 0.0, + "availability": 0.987007, + "gen_feat_1": 499.47, + "gen_feat_2": 0.51104, + "gen_feat_3": 510.35 + } + }, + { + "id": "t_remove_item_gen_1", + "task_id": "t_remove_item", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order/item (Gen Shared)", + "features": { + "latency_ms": 84.0, + "cost_usd": 0.0, + "availability": 0.986162, + "gen_feat_1": 504.01, + "gen_feat_2": 0.48957, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_get_amount_gen_1", + "task_id": "t_get_amount", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/amount (Gen Shared)", + "features": { + "latency_ms": 56.45, + "cost_usd": 0.0, + "availability": 0.980217, + "gen_feat_1": 496.14, + "gen_feat_2": 0.50654, + "gen_feat_3": 490.74 + } + }, + { + "id": "t_checkout_gen_1", + "task_id": "t_checkout", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/payment (Gen Shared)", + "features": { + "latency_ms": 151.81, + "cost_usd": 0.0, + "availability": 0.994297, + "gen_feat_1": 498.47, + "gen_feat_2": 0.487221, + "gen_feat_3": 493.19 + } + }, + { + "id": "t_charge_payment_gen_1", + "task_id": "t_charge_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA POST /payment (Gen Shared)", + "features": { + "latency_ms": 313.81, + "cost_usd": 0.02, + "availability": 0.997468, + "gen_feat_1": 510.71, + "gen_feat_2": 0.511215, + "gen_feat_3": 498.76 + } + }, + { + "id": "t_list_confirmed_gen_1", + "task_id": "t_list_confirmed", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/confirmed (Gen Shared)", + "features": { + "latency_ms": 70.26, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.98, + "gen_feat_2": 0.510011, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_ship_order_gen_1", + "task_id": "t_ship_order", + "provider_id": "p_gen_shared", + "name": "ShopA fulfillment (Gen Shared)", + "features": { + "latency_ms": 469.4, + "cost_usd": 0.05, + "availability": 0.974618, + "gen_feat_1": 487.5, + "gen_feat_2": 0.512786, + "gen_feat_3": 513.89 + } + }, + { + "id": "t_update_shipment_gen_1", + "task_id": "t_update_shipment", + "provider_id": "p_gen_shared", + "name": "ShopA PUT /order/shipment (Gen Shared)", + "features": { + "latency_ms": 94.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 502.81, + "gen_feat_2": 0.50761, + "gen_feat_3": 507.89 + } + }, + { + "id": "t_cancel_order_gen_1", + "task_id": "t_cancel_order", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order (Gen Shared)", + "features": { + "latency_ms": 86.15, + "cost_usd": 0.0, + "availability": 0.993874, + "gen_feat_1": 498.93, + "gen_feat_2": 0.503401, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_refund_payment_gen_1", + "task_id": "t_refund_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA DELETE /payment (Gen Shared)", + "features": { + "latency_ms": 236.32, + "cost_usd": 0.02, + "availability": 0.993549, + "gen_feat_1": 487.89, + "gen_feat_2": 0.503178, + "gen_feat_3": 498.93 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_create_order", + "kind": "TASK", + "task_id": "t_create_order" + }, + { + "id": "n_edit_loop", + "kind": "LOOP", + "body": { + "id": "n_edit_action", + "kind": "XOR", + "branches": [ + { + "p": 0.7, + "child": { + "id": "n_add_item_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_request_quote", + "kind": "TASK", + "task_id": "t_request_quote" + }, + { + "id": "n_get_quote", + "kind": "TASK", + "task_id": "t_get_quote" + }, + { + "id": "n_add_item", + "kind": "TASK", + "task_id": "t_add_item" + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_remove_item", + "kind": "TASK", + "task_id": "t_remove_item" + } + }, + { + "p": 0.2, + "child": { + "id": "n_get_amount", + "kind": "TASK", + "task_id": "t_get_amount" + } + } + ] + }, + "expected_iterations": 3 + }, + { + "id": "n_decide_checkout_or_cancel", + "kind": "XOR", + "branches": [ + { + "p": 0.9, + "child": { + "id": "n_checkout_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_checkout", + "kind": "TASK", + "task_id": "t_checkout" + }, + { + "id": "n_charge_payment", + "kind": "TASK", + "task_id": "t_charge_payment" + }, + { + "id": "n_after_confirm", + "kind": "XOR", + "branches": [ + { + "p": 0.95, + "child": { + "id": "n_ship_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_list_confirmed", + "kind": "TASK", + "task_id": "t_list_confirmed" + }, + { + "id": "n_ship_order", + "kind": "TASK", + "task_id": "t_ship_order" + }, + { + "id": "n_update_shipment", + "kind": "TASK", + "task_id": "t_update_shipment" + } + ] + } + }, + { + "p": 0.05, + "child": { + "id": "n_cancel_confirmed_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_cancel_confirmed", + "kind": "TASK", + "task_id": "t_cancel_order" + }, + { + "id": "n_refund_payment", + "kind": "TASK", + "task_id": "t_refund_payment" + } + ] + } + } + ] + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_cancel_before_confirm", + "kind": "TASK", + "task_id": "t_cancel_order" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "bind_shop_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_create_order", + "t_add_item", + "t_remove_item", + "t_get_amount", + "t_checkout", + "t_list_confirmed", + "t_ship_order", + "t_update_shipment", + "t_cancel_order" + ] + }, + { + "id": "bind_catalog_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_request_quote", + "t_get_quote" + ] + }, + { + "id": "bind_payment_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_charge_payment", + "t_refund_payment" + ] + }, + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 2259.82, + "hard": true + }, + { + "id": "gen_c_local_t_add_item_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_add_item" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_add_item", + "t_cancel_order" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_add_item", + "t_charge_payment" + ], + "hard": true + } + ], + "objective": { + "type": "MONO", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/pautasso2009-restful-ecommerce_mono_utility_soft.json b/experimentation/instances/pautasso2009-restful-ecommerce_mono_utility_soft.json new file mode 100644 index 0000000..de2437c --- /dev/null +++ b/experimentation/instances/pautasso2009-restful-ecommerce_mono_utility_soft.json @@ -0,0 +1,1086 @@ +{ + "metadata": { + "id": "pautasso2009-restful-ecommerce_mono_utility_soft", + "name": "RESTful e-Commerce scenario (Pautasso 2009) [mono_utility, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:01Z", + "description": "QoS-aware composition instance derived from the running e-Commerce example in Pautasso (2009) 'BPEL for REST'. QoS numbers are illustrative (the paper specifies the workflow/API but not QoS measurements).", + "paper": { + "title": "RESTful Web service composition with BPEL for REST", + "authors": "C. Pautasso", + "year": 2009, + "doi": "10.1016/j.datak.2009.02.016" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Invocation cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_shop_a", + "name": "Shop Service A" + }, + { + "id": "p_shop_b", + "name": "Shop Service B" + }, + { + "id": "p_catalog_a", + "name": "Catalog Service A" + }, + { + "id": "p_catalog_b", + "name": "Catalog Service B" + }, + { + "id": "p_payment_a", + "name": "Payment Service A" + }, + { + "id": "p_payment_b", + "name": "Payment Service B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_create_order", + "name": "Create order (POST /order)" + }, + { + "id": "t_request_quote", + "name": "Request quote (POST /product/quote)" + }, + { + "id": "t_get_quote", + "name": "Retrieve quote details (GET /quote)" + }, + { + "id": "t_add_item", + "name": "Add line item (POST /order/item)" + }, + { + "id": "t_remove_item", + "name": "Remove line item (DELETE /order/item)" + }, + { + "id": "t_get_amount", + "name": "Get order amount (GET /order/amount)" + }, + { + "id": "t_checkout", + "name": "Checkout (POST /order/payment)" + }, + { + "id": "t_charge_payment", + "name": "Charge payment (POST /payment)" + }, + { + "id": "t_list_confirmed", + "name": "List confirmed orders (GET /order/confirmed)" + }, + { + "id": "t_ship_order", + "name": "Ship order (fulfillment action within Shop binding)" + }, + { + "id": "t_update_shipment", + "name": "Update shipment info (PUT /order/shipment)" + }, + { + "id": "t_cancel_order", + "name": "Cancel order (DELETE /order)" + }, + { + "id": "t_refund_payment", + "name": "Refund payment (DELETE /payment)" + } + ], + "candidates": [ + { + "id": "c_shopA_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_a", + "name": "ShopA POST /order", + "features": { + "latency_ms": 105, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_b", + "name": "ShopB POST /order", + "features": { + "latency_ms": 130, + "cost_usd": 0.0004, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/item", + "features": { + "latency_ms": 135, + "cost_usd": 0.0008, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/item", + "features": { + "latency_ms": 160, + "cost_usd": 0.0006, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order/item", + "features": { + "latency_ms": 85, + "cost_usd": 0.0005, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order/item", + "features": { + "latency_ms": 100, + "cost_usd": 0.0003, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/amount", + "features": { + "latency_ms": 55, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/amount", + "features": { + "latency_ms": 75, + "cost_usd": 0.00018, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/payment", + "features": { + "latency_ms": 150, + "cost_usd": 0.0012, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/payment", + "features": { + "latency_ms": 185, + "cost_usd": 0.001, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/confirmed", + "features": { + "latency_ms": 70, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/confirmed", + "features": { + "latency_ms": 90, + "cost_usd": 0.0002, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_a", + "name": "ShopA fulfillment", + "features": { + "latency_ms": 480, + "cost_usd": 0.05, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_b", + "name": "ShopB fulfillment", + "features": { + "latency_ms": 520, + "cost_usd": 0.045, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_a", + "name": "ShopA PUT /order/shipment", + "features": { + "latency_ms": 95, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_b", + "name": "ShopB PUT /order/shipment", + "features": { + "latency_ms": 110, + "cost_usd": 0.00045, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order", + "features": { + "latency_ms": 85, + "cost_usd": 0.00035, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order", + "features": { + "latency_ms": 95, + "cost_usd": 0.00025, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA POST /product/quote", + "features": { + "latency_ms": 120, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB POST /product/quote", + "features": { + "latency_ms": 210, + "cost_usd": 0.0015, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA GET /quote", + "features": { + "latency_ms": 85, + "cost_usd": 0.001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB GET /quote", + "features": { + "latency_ms": 155, + "cost_usd": 0.0007, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_a", + "name": "PaymentA POST /payment", + "features": { + "latency_ms": 320, + "cost_usd": 0.02, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_b", + "name": "PaymentB POST /payment", + "features": { + "latency_ms": 380, + "cost_usd": 0.017, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_a", + "name": "PaymentA DELETE /payment", + "features": { + "latency_ms": 240, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_b", + "name": "PaymentB DELETE /payment", + "features": { + "latency_ms": 290, + "cost_usd": 0.013, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_create_order_gen_1", + "task_id": "t_create_order", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order (Gen Shared)", + "features": { + "latency_ms": 105.45, + "cost_usd": 0.0, + "availability": 0.997768, + "gen_feat_1": 512.31, + "gen_feat_2": 0.494924, + "gen_feat_3": 495.49 + } + }, + { + "id": "t_request_quote_gen_1", + "task_id": "t_request_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA POST /product/quote (Gen Shared)", + "features": { + "latency_ms": 122.37, + "cost_usd": 0.0, + "availability": 0.979755, + "gen_feat_1": 507.51, + "gen_feat_2": 0.493998, + "gen_feat_3": 513.92 + } + }, + { + "id": "t_get_quote_gen_1", + "task_id": "t_get_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA GET /quote (Gen Shared)", + "features": { + "latency_ms": 84.6, + "cost_usd": 0.0, + "availability": 0.999119, + "gen_feat_1": 499.61, + "gen_feat_2": 0.498885, + "gen_feat_3": 492.6 + } + }, + { + "id": "t_add_item_gen_1", + "task_id": "t_add_item", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/item (Gen Shared)", + "features": { + "latency_ms": 134.46, + "cost_usd": 0.0, + "availability": 0.987007, + "gen_feat_1": 499.47, + "gen_feat_2": 0.51104, + "gen_feat_3": 510.35 + } + }, + { + "id": "t_remove_item_gen_1", + "task_id": "t_remove_item", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order/item (Gen Shared)", + "features": { + "latency_ms": 84.0, + "cost_usd": 0.0, + "availability": 0.986162, + "gen_feat_1": 504.01, + "gen_feat_2": 0.48957, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_get_amount_gen_1", + "task_id": "t_get_amount", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/amount (Gen Shared)", + "features": { + "latency_ms": 56.45, + "cost_usd": 0.0, + "availability": 0.980217, + "gen_feat_1": 496.14, + "gen_feat_2": 0.50654, + "gen_feat_3": 490.74 + } + }, + { + "id": "t_checkout_gen_1", + "task_id": "t_checkout", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/payment (Gen Shared)", + "features": { + "latency_ms": 151.81, + "cost_usd": 0.0, + "availability": 0.994297, + "gen_feat_1": 498.47, + "gen_feat_2": 0.487221, + "gen_feat_3": 493.19 + } + }, + { + "id": "t_charge_payment_gen_1", + "task_id": "t_charge_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA POST /payment (Gen Shared)", + "features": { + "latency_ms": 313.81, + "cost_usd": 0.02, + "availability": 0.997468, + "gen_feat_1": 510.71, + "gen_feat_2": 0.511215, + "gen_feat_3": 498.76 + } + }, + { + "id": "t_list_confirmed_gen_1", + "task_id": "t_list_confirmed", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/confirmed (Gen Shared)", + "features": { + "latency_ms": 70.26, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.98, + "gen_feat_2": 0.510011, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_ship_order_gen_1", + "task_id": "t_ship_order", + "provider_id": "p_gen_shared", + "name": "ShopA fulfillment (Gen Shared)", + "features": { + "latency_ms": 469.4, + "cost_usd": 0.05, + "availability": 0.974618, + "gen_feat_1": 487.5, + "gen_feat_2": 0.512786, + "gen_feat_3": 513.89 + } + }, + { + "id": "t_update_shipment_gen_1", + "task_id": "t_update_shipment", + "provider_id": "p_gen_shared", + "name": "ShopA PUT /order/shipment (Gen Shared)", + "features": { + "latency_ms": 94.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 502.81, + "gen_feat_2": 0.50761, + "gen_feat_3": 507.89 + } + }, + { + "id": "t_cancel_order_gen_1", + "task_id": "t_cancel_order", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order (Gen Shared)", + "features": { + "latency_ms": 86.15, + "cost_usd": 0.0, + "availability": 0.993874, + "gen_feat_1": 498.93, + "gen_feat_2": 0.503401, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_refund_payment_gen_1", + "task_id": "t_refund_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA DELETE /payment (Gen Shared)", + "features": { + "latency_ms": 236.32, + "cost_usd": 0.02, + "availability": 0.993549, + "gen_feat_1": 487.89, + "gen_feat_2": 0.503178, + "gen_feat_3": 498.93 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_create_order", + "kind": "TASK", + "task_id": "t_create_order" + }, + { + "id": "n_edit_loop", + "kind": "LOOP", + "body": { + "id": "n_edit_action", + "kind": "XOR", + "branches": [ + { + "p": 0.7, + "child": { + "id": "n_add_item_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_request_quote", + "kind": "TASK", + "task_id": "t_request_quote" + }, + { + "id": "n_get_quote", + "kind": "TASK", + "task_id": "t_get_quote" + }, + { + "id": "n_add_item", + "kind": "TASK", + "task_id": "t_add_item" + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_remove_item", + "kind": "TASK", + "task_id": "t_remove_item" + } + }, + { + "p": 0.2, + "child": { + "id": "n_get_amount", + "kind": "TASK", + "task_id": "t_get_amount" + } + } + ] + }, + "expected_iterations": 3 + }, + { + "id": "n_decide_checkout_or_cancel", + "kind": "XOR", + "branches": [ + { + "p": 0.9, + "child": { + "id": "n_checkout_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_checkout", + "kind": "TASK", + "task_id": "t_checkout" + }, + { + "id": "n_charge_payment", + "kind": "TASK", + "task_id": "t_charge_payment" + }, + { + "id": "n_after_confirm", + "kind": "XOR", + "branches": [ + { + "p": 0.95, + "child": { + "id": "n_ship_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_list_confirmed", + "kind": "TASK", + "task_id": "t_list_confirmed" + }, + { + "id": "n_ship_order", + "kind": "TASK", + "task_id": "t_ship_order" + }, + { + "id": "n_update_shipment", + "kind": "TASK", + "task_id": "t_update_shipment" + } + ] + } + }, + { + "p": 0.05, + "child": { + "id": "n_cancel_confirmed_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_cancel_confirmed", + "kind": "TASK", + "task_id": "t_cancel_order" + }, + { + "id": "n_refund_payment", + "kind": "TASK", + "task_id": "t_refund_payment" + } + ] + } + } + ] + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_cancel_before_confirm", + "kind": "TASK", + "task_id": "t_cancel_order" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "bind_shop_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_create_order", + "t_add_item", + "t_remove_item", + "t_get_amount", + "t_checkout", + "t_list_confirmed", + "t_ship_order", + "t_update_shipment", + "t_cancel_order" + ], + "hard": false + }, + { + "id": "bind_catalog_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_request_quote", + "t_get_quote" + ], + "hard": false + }, + { + "id": "bind_payment_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_charge_payment", + "t_refund_payment" + ], + "hard": false + }, + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 2259.82, + "hard": false + }, + { + "id": "gen_c_local_t_add_item_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_add_item" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_add_item", + "t_cancel_order" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_add_item", + "t_charge_payment" + ], + "hard": false + } + ], + "objective": { + "type": "MONO", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "latency_ms" + ], + "weights": { + "availability": 0.17, + "cost_usd": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "latency_ms": 0.16 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/pautasso2009-restful-ecommerce_multi_hard.json b/experimentation/instances/pautasso2009-restful-ecommerce_multi_hard.json new file mode 100644 index 0000000..4239d5b --- /dev/null +++ b/experimentation/instances/pautasso2009-restful-ecommerce_multi_hard.json @@ -0,0 +1,1077 @@ +{ + "metadata": { + "id": "pautasso2009-restful-ecommerce_multi_hard", + "name": "RESTful e-Commerce scenario (Pautasso 2009) [multi, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:02Z", + "description": "QoS-aware composition instance derived from the running e-Commerce example in Pautasso (2009) 'BPEL for REST'. QoS numbers are illustrative (the paper specifies the workflow/API but not QoS measurements).", + "paper": { + "title": "RESTful Web service composition with BPEL for REST", + "authors": "C. Pautasso", + "year": 2009, + "doi": "10.1016/j.datak.2009.02.016" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Invocation cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_shop_a", + "name": "Shop Service A" + }, + { + "id": "p_shop_b", + "name": "Shop Service B" + }, + { + "id": "p_catalog_a", + "name": "Catalog Service A" + }, + { + "id": "p_catalog_b", + "name": "Catalog Service B" + }, + { + "id": "p_payment_a", + "name": "Payment Service A" + }, + { + "id": "p_payment_b", + "name": "Payment Service B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_create_order", + "name": "Create order (POST /order)" + }, + { + "id": "t_request_quote", + "name": "Request quote (POST /product/quote)" + }, + { + "id": "t_get_quote", + "name": "Retrieve quote details (GET /quote)" + }, + { + "id": "t_add_item", + "name": "Add line item (POST /order/item)" + }, + { + "id": "t_remove_item", + "name": "Remove line item (DELETE /order/item)" + }, + { + "id": "t_get_amount", + "name": "Get order amount (GET /order/amount)" + }, + { + "id": "t_checkout", + "name": "Checkout (POST /order/payment)" + }, + { + "id": "t_charge_payment", + "name": "Charge payment (POST /payment)" + }, + { + "id": "t_list_confirmed", + "name": "List confirmed orders (GET /order/confirmed)" + }, + { + "id": "t_ship_order", + "name": "Ship order (fulfillment action within Shop binding)" + }, + { + "id": "t_update_shipment", + "name": "Update shipment info (PUT /order/shipment)" + }, + { + "id": "t_cancel_order", + "name": "Cancel order (DELETE /order)" + }, + { + "id": "t_refund_payment", + "name": "Refund payment (DELETE /payment)" + } + ], + "candidates": [ + { + "id": "c_shopA_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_a", + "name": "ShopA POST /order", + "features": { + "latency_ms": 105, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_b", + "name": "ShopB POST /order", + "features": { + "latency_ms": 130, + "cost_usd": 0.0004, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/item", + "features": { + "latency_ms": 135, + "cost_usd": 0.0008, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/item", + "features": { + "latency_ms": 160, + "cost_usd": 0.0006, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order/item", + "features": { + "latency_ms": 85, + "cost_usd": 0.0005, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order/item", + "features": { + "latency_ms": 100, + "cost_usd": 0.0003, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/amount", + "features": { + "latency_ms": 55, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/amount", + "features": { + "latency_ms": 75, + "cost_usd": 0.00018, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/payment", + "features": { + "latency_ms": 150, + "cost_usd": 0.0012, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/payment", + "features": { + "latency_ms": 185, + "cost_usd": 0.001, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/confirmed", + "features": { + "latency_ms": 70, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/confirmed", + "features": { + "latency_ms": 90, + "cost_usd": 0.0002, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_a", + "name": "ShopA fulfillment", + "features": { + "latency_ms": 480, + "cost_usd": 0.05, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_b", + "name": "ShopB fulfillment", + "features": { + "latency_ms": 520, + "cost_usd": 0.045, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_a", + "name": "ShopA PUT /order/shipment", + "features": { + "latency_ms": 95, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_b", + "name": "ShopB PUT /order/shipment", + "features": { + "latency_ms": 110, + "cost_usd": 0.00045, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order", + "features": { + "latency_ms": 85, + "cost_usd": 0.00035, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order", + "features": { + "latency_ms": 95, + "cost_usd": 0.00025, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA POST /product/quote", + "features": { + "latency_ms": 120, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB POST /product/quote", + "features": { + "latency_ms": 210, + "cost_usd": 0.0015, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA GET /quote", + "features": { + "latency_ms": 85, + "cost_usd": 0.001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB GET /quote", + "features": { + "latency_ms": 155, + "cost_usd": 0.0007, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_a", + "name": "PaymentA POST /payment", + "features": { + "latency_ms": 320, + "cost_usd": 0.02, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_b", + "name": "PaymentB POST /payment", + "features": { + "latency_ms": 380, + "cost_usd": 0.017, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_a", + "name": "PaymentA DELETE /payment", + "features": { + "latency_ms": 240, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_b", + "name": "PaymentB DELETE /payment", + "features": { + "latency_ms": 290, + "cost_usd": 0.013, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_create_order_gen_1", + "task_id": "t_create_order", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order (Gen Shared)", + "features": { + "latency_ms": 105.45, + "cost_usd": 0.0, + "availability": 0.997768, + "gen_feat_1": 512.31, + "gen_feat_2": 0.494924, + "gen_feat_3": 495.49 + } + }, + { + "id": "t_request_quote_gen_1", + "task_id": "t_request_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA POST /product/quote (Gen Shared)", + "features": { + "latency_ms": 122.37, + "cost_usd": 0.0, + "availability": 0.979755, + "gen_feat_1": 507.51, + "gen_feat_2": 0.493998, + "gen_feat_3": 513.92 + } + }, + { + "id": "t_get_quote_gen_1", + "task_id": "t_get_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA GET /quote (Gen Shared)", + "features": { + "latency_ms": 84.6, + "cost_usd": 0.0, + "availability": 0.999119, + "gen_feat_1": 499.61, + "gen_feat_2": 0.498885, + "gen_feat_3": 492.6 + } + }, + { + "id": "t_add_item_gen_1", + "task_id": "t_add_item", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/item (Gen Shared)", + "features": { + "latency_ms": 134.46, + "cost_usd": 0.0, + "availability": 0.987007, + "gen_feat_1": 499.47, + "gen_feat_2": 0.51104, + "gen_feat_3": 510.35 + } + }, + { + "id": "t_remove_item_gen_1", + "task_id": "t_remove_item", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order/item (Gen Shared)", + "features": { + "latency_ms": 84.0, + "cost_usd": 0.0, + "availability": 0.986162, + "gen_feat_1": 504.01, + "gen_feat_2": 0.48957, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_get_amount_gen_1", + "task_id": "t_get_amount", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/amount (Gen Shared)", + "features": { + "latency_ms": 56.45, + "cost_usd": 0.0, + "availability": 0.980217, + "gen_feat_1": 496.14, + "gen_feat_2": 0.50654, + "gen_feat_3": 490.74 + } + }, + { + "id": "t_checkout_gen_1", + "task_id": "t_checkout", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/payment (Gen Shared)", + "features": { + "latency_ms": 151.81, + "cost_usd": 0.0, + "availability": 0.994297, + "gen_feat_1": 498.47, + "gen_feat_2": 0.487221, + "gen_feat_3": 493.19 + } + }, + { + "id": "t_charge_payment_gen_1", + "task_id": "t_charge_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA POST /payment (Gen Shared)", + "features": { + "latency_ms": 313.81, + "cost_usd": 0.02, + "availability": 0.997468, + "gen_feat_1": 510.71, + "gen_feat_2": 0.511215, + "gen_feat_3": 498.76 + } + }, + { + "id": "t_list_confirmed_gen_1", + "task_id": "t_list_confirmed", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/confirmed (Gen Shared)", + "features": { + "latency_ms": 70.26, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.98, + "gen_feat_2": 0.510011, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_ship_order_gen_1", + "task_id": "t_ship_order", + "provider_id": "p_gen_shared", + "name": "ShopA fulfillment (Gen Shared)", + "features": { + "latency_ms": 469.4, + "cost_usd": 0.05, + "availability": 0.974618, + "gen_feat_1": 487.5, + "gen_feat_2": 0.512786, + "gen_feat_3": 513.89 + } + }, + { + "id": "t_update_shipment_gen_1", + "task_id": "t_update_shipment", + "provider_id": "p_gen_shared", + "name": "ShopA PUT /order/shipment (Gen Shared)", + "features": { + "latency_ms": 94.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 502.81, + "gen_feat_2": 0.50761, + "gen_feat_3": 507.89 + } + }, + { + "id": "t_cancel_order_gen_1", + "task_id": "t_cancel_order", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order (Gen Shared)", + "features": { + "latency_ms": 86.15, + "cost_usd": 0.0, + "availability": 0.993874, + "gen_feat_1": 498.93, + "gen_feat_2": 0.503401, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_refund_payment_gen_1", + "task_id": "t_refund_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA DELETE /payment (Gen Shared)", + "features": { + "latency_ms": 236.32, + "cost_usd": 0.02, + "availability": 0.993549, + "gen_feat_1": 487.89, + "gen_feat_2": 0.503178, + "gen_feat_3": 498.93 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_create_order", + "kind": "TASK", + "task_id": "t_create_order" + }, + { + "id": "n_edit_loop", + "kind": "LOOP", + "body": { + "id": "n_edit_action", + "kind": "XOR", + "branches": [ + { + "p": 0.7, + "child": { + "id": "n_add_item_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_request_quote", + "kind": "TASK", + "task_id": "t_request_quote" + }, + { + "id": "n_get_quote", + "kind": "TASK", + "task_id": "t_get_quote" + }, + { + "id": "n_add_item", + "kind": "TASK", + "task_id": "t_add_item" + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_remove_item", + "kind": "TASK", + "task_id": "t_remove_item" + } + }, + { + "p": 0.2, + "child": { + "id": "n_get_amount", + "kind": "TASK", + "task_id": "t_get_amount" + } + } + ] + }, + "expected_iterations": 3 + }, + { + "id": "n_decide_checkout_or_cancel", + "kind": "XOR", + "branches": [ + { + "p": 0.9, + "child": { + "id": "n_checkout_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_checkout", + "kind": "TASK", + "task_id": "t_checkout" + }, + { + "id": "n_charge_payment", + "kind": "TASK", + "task_id": "t_charge_payment" + }, + { + "id": "n_after_confirm", + "kind": "XOR", + "branches": [ + { + "p": 0.95, + "child": { + "id": "n_ship_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_list_confirmed", + "kind": "TASK", + "task_id": "t_list_confirmed" + }, + { + "id": "n_ship_order", + "kind": "TASK", + "task_id": "t_ship_order" + }, + { + "id": "n_update_shipment", + "kind": "TASK", + "task_id": "t_update_shipment" + } + ] + } + }, + { + "p": 0.05, + "child": { + "id": "n_cancel_confirmed_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_cancel_confirmed", + "kind": "TASK", + "task_id": "t_cancel_order" + }, + { + "id": "n_refund_payment", + "kind": "TASK", + "task_id": "t_refund_payment" + } + ] + } + } + ] + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_cancel_before_confirm", + "kind": "TASK", + "task_id": "t_cancel_order" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "bind_shop_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_create_order", + "t_add_item", + "t_remove_item", + "t_get_amount", + "t_checkout", + "t_list_confirmed", + "t_ship_order", + "t_update_shipment", + "t_cancel_order" + ] + }, + { + "id": "bind_catalog_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_request_quote", + "t_get_quote" + ] + }, + { + "id": "bind_payment_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_charge_payment", + "t_refund_payment" + ] + }, + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1866.14, + "hard": true + }, + { + "id": "gen_c_local_t_add_item_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_add_item" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_add_item", + "t_cancel_order" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_add_item", + "t_refund_payment" + ], + "hard": true + } + ], + "objective": { + "type": "MULTI", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1" + ], + "weights": { + "availability": 0.34, + "cost_usd": 0.33, + "gen_feat_1": 0.33 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/pautasso2009-restful-ecommerce_multi_soft.json b/experimentation/instances/pautasso2009-restful-ecommerce_multi_soft.json new file mode 100644 index 0000000..aec203e --- /dev/null +++ b/experimentation/instances/pautasso2009-restful-ecommerce_multi_soft.json @@ -0,0 +1,1080 @@ +{ + "metadata": { + "id": "pautasso2009-restful-ecommerce_multi_soft", + "name": "RESTful e-Commerce scenario (Pautasso 2009) [multi, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:03Z", + "description": "QoS-aware composition instance derived from the running e-Commerce example in Pautasso (2009) 'BPEL for REST'. QoS numbers are illustrative (the paper specifies the workflow/API but not QoS measurements).", + "paper": { + "title": "RESTful Web service composition with BPEL for REST", + "authors": "C. Pautasso", + "year": 2009, + "doi": "10.1016/j.datak.2009.02.016" + } + }, + "features": [ + { + "id": "latency_ms", + "name": "End-to-end response time", + "direction": "MINIMIZE", + "unit": "ms", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 5000 + } + }, + { + "id": "cost_usd", + "name": "Invocation cost", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "availability", + "name": "Availability", + "direction": "MAXIMIZE", + "unit": "prob", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_shop_a", + "name": "Shop Service A" + }, + { + "id": "p_shop_b", + "name": "Shop Service B" + }, + { + "id": "p_catalog_a", + "name": "Catalog Service A" + }, + { + "id": "p_catalog_b", + "name": "Catalog Service B" + }, + { + "id": "p_payment_a", + "name": "Payment Service A" + }, + { + "id": "p_payment_b", + "name": "Payment Service B" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_create_order", + "name": "Create order (POST /order)" + }, + { + "id": "t_request_quote", + "name": "Request quote (POST /product/quote)" + }, + { + "id": "t_get_quote", + "name": "Retrieve quote details (GET /quote)" + }, + { + "id": "t_add_item", + "name": "Add line item (POST /order/item)" + }, + { + "id": "t_remove_item", + "name": "Remove line item (DELETE /order/item)" + }, + { + "id": "t_get_amount", + "name": "Get order amount (GET /order/amount)" + }, + { + "id": "t_checkout", + "name": "Checkout (POST /order/payment)" + }, + { + "id": "t_charge_payment", + "name": "Charge payment (POST /payment)" + }, + { + "id": "t_list_confirmed", + "name": "List confirmed orders (GET /order/confirmed)" + }, + { + "id": "t_ship_order", + "name": "Ship order (fulfillment action within Shop binding)" + }, + { + "id": "t_update_shipment", + "name": "Update shipment info (PUT /order/shipment)" + }, + { + "id": "t_cancel_order", + "name": "Cancel order (DELETE /order)" + }, + { + "id": "t_refund_payment", + "name": "Refund payment (DELETE /payment)" + } + ], + "candidates": [ + { + "id": "c_shopA_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_a", + "name": "ShopA POST /order", + "features": { + "latency_ms": 105, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_create_order", + "task_id": "t_create_order", + "provider_id": "p_shop_b", + "name": "ShopB POST /order", + "features": { + "latency_ms": 130, + "cost_usd": 0.0004, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/item", + "features": { + "latency_ms": 135, + "cost_usd": 0.0008, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_add_item", + "task_id": "t_add_item", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/item", + "features": { + "latency_ms": 160, + "cost_usd": 0.0006, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order/item", + "features": { + "latency_ms": 85, + "cost_usd": 0.0005, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_remove_item", + "task_id": "t_remove_item", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order/item", + "features": { + "latency_ms": 100, + "cost_usd": 0.0003, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/amount", + "features": { + "latency_ms": 55, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_get_amount", + "task_id": "t_get_amount", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/amount", + "features": { + "latency_ms": 75, + "cost_usd": 0.00018, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_a", + "name": "ShopA POST /order/payment", + "features": { + "latency_ms": 150, + "cost_usd": 0.0012, + "availability": 0.996, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_checkout", + "task_id": "t_checkout", + "provider_id": "p_shop_b", + "name": "ShopB POST /order/payment", + "features": { + "latency_ms": 185, + "cost_usd": 0.001, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_a", + "name": "ShopA GET /order/confirmed", + "features": { + "latency_ms": 70, + "cost_usd": 0.00025, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_list_confirmed", + "task_id": "t_list_confirmed", + "provider_id": "p_shop_b", + "name": "ShopB GET /order/confirmed", + "features": { + "latency_ms": 90, + "cost_usd": 0.0002, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_a", + "name": "ShopA fulfillment", + "features": { + "latency_ms": 480, + "cost_usd": 0.05, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_ship_order", + "task_id": "t_ship_order", + "provider_id": "p_shop_b", + "name": "ShopB fulfillment", + "features": { + "latency_ms": 520, + "cost_usd": 0.045, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_a", + "name": "ShopA PUT /order/shipment", + "features": { + "latency_ms": 95, + "cost_usd": 0.0006, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_update_shipment", + "task_id": "t_update_shipment", + "provider_id": "p_shop_b", + "name": "ShopB PUT /order/shipment", + "features": { + "latency_ms": 110, + "cost_usd": 0.00045, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopA_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_a", + "name": "ShopA DELETE /order", + "features": { + "latency_ms": 85, + "cost_usd": 0.00035, + "availability": 0.998, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopB_cancel_order", + "task_id": "t_cancel_order", + "provider_id": "p_shop_b", + "name": "ShopB DELETE /order", + "features": { + "latency_ms": 95, + "cost_usd": 0.00025, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA POST /product/quote", + "features": { + "latency_ms": 120, + "cost_usd": 0.002, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_request_quote", + "task_id": "t_request_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB POST /product/quote", + "features": { + "latency_ms": 210, + "cost_usd": 0.0015, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogA_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_a", + "name": "CatalogA GET /quote", + "features": { + "latency_ms": 85, + "cost_usd": 0.001, + "availability": 0.995, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_catalogB_get_quote", + "task_id": "t_get_quote", + "provider_id": "p_catalog_b", + "name": "CatalogB GET /quote", + "features": { + "latency_ms": 155, + "cost_usd": 0.0007, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_a", + "name": "PaymentA POST /payment", + "features": { + "latency_ms": 320, + "cost_usd": 0.02, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_charge", + "task_id": "t_charge_payment", + "provider_id": "p_payment_b", + "name": "PaymentB POST /payment", + "features": { + "latency_ms": 380, + "cost_usd": 0.017, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentA_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_a", + "name": "PaymentA DELETE /payment", + "features": { + "latency_ms": 240, + "cost_usd": 0.015, + "availability": 0.997, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_paymentB_refund", + "task_id": "t_refund_payment", + "provider_id": "p_payment_b", + "name": "PaymentB DELETE /payment", + "features": { + "latency_ms": 290, + "cost_usd": 0.013, + "availability": 0.999, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_create_order_gen_1", + "task_id": "t_create_order", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order (Gen Shared)", + "features": { + "latency_ms": 105.45, + "cost_usd": 0.0, + "availability": 0.997768, + "gen_feat_1": 512.31, + "gen_feat_2": 0.494924, + "gen_feat_3": 495.49 + } + }, + { + "id": "t_request_quote_gen_1", + "task_id": "t_request_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA POST /product/quote (Gen Shared)", + "features": { + "latency_ms": 122.37, + "cost_usd": 0.0, + "availability": 0.979755, + "gen_feat_1": 507.51, + "gen_feat_2": 0.493998, + "gen_feat_3": 513.92 + } + }, + { + "id": "t_get_quote_gen_1", + "task_id": "t_get_quote", + "provider_id": "p_gen_shared", + "name": "CatalogA GET /quote (Gen Shared)", + "features": { + "latency_ms": 84.6, + "cost_usd": 0.0, + "availability": 0.999119, + "gen_feat_1": 499.61, + "gen_feat_2": 0.498885, + "gen_feat_3": 492.6 + } + }, + { + "id": "t_add_item_gen_1", + "task_id": "t_add_item", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/item (Gen Shared)", + "features": { + "latency_ms": 134.46, + "cost_usd": 0.0, + "availability": 0.987007, + "gen_feat_1": 499.47, + "gen_feat_2": 0.51104, + "gen_feat_3": 510.35 + } + }, + { + "id": "t_remove_item_gen_1", + "task_id": "t_remove_item", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order/item (Gen Shared)", + "features": { + "latency_ms": 84.0, + "cost_usd": 0.0, + "availability": 0.986162, + "gen_feat_1": 504.01, + "gen_feat_2": 0.48957, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_get_amount_gen_1", + "task_id": "t_get_amount", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/amount (Gen Shared)", + "features": { + "latency_ms": 56.45, + "cost_usd": 0.0, + "availability": 0.980217, + "gen_feat_1": 496.14, + "gen_feat_2": 0.50654, + "gen_feat_3": 490.74 + } + }, + { + "id": "t_checkout_gen_1", + "task_id": "t_checkout", + "provider_id": "p_gen_shared", + "name": "ShopA POST /order/payment (Gen Shared)", + "features": { + "latency_ms": 151.81, + "cost_usd": 0.0, + "availability": 0.994297, + "gen_feat_1": 498.47, + "gen_feat_2": 0.487221, + "gen_feat_3": 493.19 + } + }, + { + "id": "t_charge_payment_gen_1", + "task_id": "t_charge_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA POST /payment (Gen Shared)", + "features": { + "latency_ms": 313.81, + "cost_usd": 0.02, + "availability": 0.997468, + "gen_feat_1": 510.71, + "gen_feat_2": 0.511215, + "gen_feat_3": 498.76 + } + }, + { + "id": "t_list_confirmed_gen_1", + "task_id": "t_list_confirmed", + "provider_id": "p_gen_shared", + "name": "ShopA GET /order/confirmed (Gen Shared)", + "features": { + "latency_ms": 70.26, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 490.98, + "gen_feat_2": 0.510011, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_ship_order_gen_1", + "task_id": "t_ship_order", + "provider_id": "p_gen_shared", + "name": "ShopA fulfillment (Gen Shared)", + "features": { + "latency_ms": 469.4, + "cost_usd": 0.05, + "availability": 0.974618, + "gen_feat_1": 487.5, + "gen_feat_2": 0.512786, + "gen_feat_3": 513.89 + } + }, + { + "id": "t_update_shipment_gen_1", + "task_id": "t_update_shipment", + "provider_id": "p_gen_shared", + "name": "ShopA PUT /order/shipment (Gen Shared)", + "features": { + "latency_ms": 94.57, + "cost_usd": 0.0, + "availability": 1.0, + "gen_feat_1": 502.81, + "gen_feat_2": 0.50761, + "gen_feat_3": 507.89 + } + }, + { + "id": "t_cancel_order_gen_1", + "task_id": "t_cancel_order", + "provider_id": "p_gen_shared", + "name": "ShopA DELETE /order (Gen Shared)", + "features": { + "latency_ms": 86.15, + "cost_usd": 0.0, + "availability": 0.993874, + "gen_feat_1": 498.93, + "gen_feat_2": 0.503401, + "gen_feat_3": 512.39 + } + }, + { + "id": "t_refund_payment_gen_1", + "task_id": "t_refund_payment", + "provider_id": "p_gen_shared", + "name": "PaymentA DELETE /payment (Gen Shared)", + "features": { + "latency_ms": 236.32, + "cost_usd": 0.02, + "availability": 0.993549, + "gen_feat_1": 487.89, + "gen_feat_2": 0.503178, + "gen_feat_3": 498.93 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_create_order", + "kind": "TASK", + "task_id": "t_create_order" + }, + { + "id": "n_edit_loop", + "kind": "LOOP", + "body": { + "id": "n_edit_action", + "kind": "XOR", + "branches": [ + { + "p": 0.7, + "child": { + "id": "n_add_item_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_request_quote", + "kind": "TASK", + "task_id": "t_request_quote" + }, + { + "id": "n_get_quote", + "kind": "TASK", + "task_id": "t_get_quote" + }, + { + "id": "n_add_item", + "kind": "TASK", + "task_id": "t_add_item" + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_remove_item", + "kind": "TASK", + "task_id": "t_remove_item" + } + }, + { + "p": 0.2, + "child": { + "id": "n_get_amount", + "kind": "TASK", + "task_id": "t_get_amount" + } + } + ] + }, + "expected_iterations": 3 + }, + { + "id": "n_decide_checkout_or_cancel", + "kind": "XOR", + "branches": [ + { + "p": 0.9, + "child": { + "id": "n_checkout_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_checkout", + "kind": "TASK", + "task_id": "t_checkout" + }, + { + "id": "n_charge_payment", + "kind": "TASK", + "task_id": "t_charge_payment" + }, + { + "id": "n_after_confirm", + "kind": "XOR", + "branches": [ + { + "p": 0.95, + "child": { + "id": "n_ship_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_list_confirmed", + "kind": "TASK", + "task_id": "t_list_confirmed" + }, + { + "id": "n_ship_order", + "kind": "TASK", + "task_id": "t_ship_order" + }, + { + "id": "n_update_shipment", + "kind": "TASK", + "task_id": "t_update_shipment" + } + ] + } + }, + { + "p": 0.05, + "child": { + "id": "n_cancel_confirmed_seq", + "kind": "SEQ", + "children": [ + { + "id": "n_cancel_confirmed", + "kind": "TASK", + "task_id": "t_cancel_order" + }, + { + "id": "n_refund_payment", + "kind": "TASK", + "task_id": "t_refund_payment" + } + ] + } + } + ] + } + ] + } + }, + { + "p": 0.1, + "child": { + "id": "n_cancel_before_confirm", + "kind": "TASK", + "task_id": "t_cancel_order" + } + } + ] + } + ] + } + }, + "aggregation_policies": { + "latency_ms": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "cost_usd": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "availability": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + }, + "xor": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "bind_shop_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_create_order", + "t_add_item", + "t_remove_item", + "t_get_amount", + "t_checkout", + "t_list_confirmed", + "t_ship_order", + "t_update_shipment", + "t_cancel_order" + ], + "hard": false + }, + { + "id": "bind_catalog_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_request_quote", + "t_get_quote" + ], + "hard": false + }, + { + "id": "bind_payment_mono_provider", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_charge_payment", + "t_refund_payment" + ], + "hard": false + }, + { + "id": "gen_c_global_latency_ms_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "op": "<=", + "value": 1866.14, + "hard": false + }, + { + "id": "gen_c_local_t_add_item_cost_usd_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_add_item" + ], + "attribute_id": "cost_usd", + "op": "<=", + "value": 0.0, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_add_item", + "t_cancel_order" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_add_item", + "t_refund_payment" + ], + "hard": false + } + ], + "objective": { + "type": "MULTI", + "targets": [ + "availability", + "cost_usd", + "gen_feat_1" + ], + "weights": { + "availability": 0.34, + "cost_usd": 0.33, + "gen_feat_1": 0.33 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/zhang2014-entertainment-planner-running-example_many_hard.json b/experimentation/instances/zhang2014-entertainment-planner-running-example_many_hard.json new file mode 100644 index 0000000..cf07a6b --- /dev/null +++ b/experimentation/instances/zhang2014-entertainment-planner-running-example_many_hard.json @@ -0,0 +1,4540 @@ +{ + "metadata": { + "id": "zhang2014-entertainment-planner-running-example_many_hard", + "name": "Personal Entertainment Planner (Zhang et al. 2014) [many, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:05Z", + "description": "Modeled from the motivating example in 'Context-aware Generic Service Discovery and Service Composition' (IEEE MobServ 2014).", + "paper": { + "title": "Context-aware Generic Service Discovery and Service Composition", + "authors": "Y. Zhang et al.", + "year": 2014, + "doi": "10.1109/MobServ.2014.27" + } + }, + "features": [ + { + "id": "cost", + "name": "Total money cost (USD)", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "time", + "name": "Total time cost (minutes)", + "direction": "MINIMIZE", + "unit": "min", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1440 + } + }, + { + "id": "distance", + "name": "Distance from user's current location (meters)", + "direction": "MINIMIZE", + "unit": "m", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 50000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_rest_autre_saison", + "name": "Restaurant L’Autre Saison" + }, + { + "id": "p_cinema_banque_scotia", + "name": "Cinema Banque Scotia Montreal" + }, + { + "id": "p_seven_night_club", + "name": "Seven Night Club" + }, + { + "id": "p_local_shopping", + "name": "Local Shopping (nearby venue)" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_dining", + "name": "Restaurant / Dining activity" + }, + { + "id": "t_shopping", + "name": "Shopping activity" + }, + { + "id": "t_movie", + "name": "Movie activity" + } + ], + "candidates": [ + { + "id": "c_dining_autre_saison", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison", + "features": { + "cost": 20, + "time": 60, + "distance": 1600, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_dining_seven_night_club", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Seven Night Club", + "features": { + "cost": 20, + "time": 60, + "distance": 1800, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopping_local", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue", + "features": { + "cost": 20, + "time": 45, + "distance": 1200, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_movie_the_help_banque_scotia", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal", + "features": { + "cost": 10, + "time": 135, + "distance": 1700, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_dining_gen_1", + "task_id": "t_dining", + "provider_id": "p_gen_shared", + "name": "Dinner at Restaurant L’Autre Saison (Gen Shared)", + "features": { + "cost": 20.2, + "time": 59.79, + "distance": 1570.05, + "gen_feat_1": 508.24, + "gen_feat_2": 0.514901, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_shopping_gen_1", + "task_id": "t_shopping", + "provider_id": "p_gen_shared", + "name": "Shopping at a nearby venue (Gen Shared)", + "features": { + "cost": 19.87, + "time": 44.98, + "distance": 1189.95, + "gen_feat_1": 485.24, + "gen_feat_2": 0.486287, + "gen_feat_3": 500.42 + } + }, + { + "id": "t_movie_gen_1", + "task_id": "t_movie", + "provider_id": "p_gen_shared", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen Shared)", + "features": { + "cost": 9.82, + "time": 134.28, + "distance": 1742.9, + "gen_feat_1": 512.03, + "gen_feat_2": 0.505972, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_dining_gen_2", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.53, + "time": 59.13, + "distance": 1559.02, + "gen_feat_1": 498.66, + "gen_feat_2": 0.488957, + "gen_feat_3": 503.61 + } + }, + { + "id": "t_dining_gen_3", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.94, + "time": 58.5, + "distance": 1591.09, + "gen_feat_1": 495.96, + "gen_feat_2": 0.504969, + "gen_feat_3": 506.77 + } + }, + { + "id": "t_dining_gen_4", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.8, + "time": 61.46, + "distance": 1629.91, + "gen_feat_1": 510.53, + "gen_feat_2": 0.508, + "gen_feat_3": 491.98 + } + }, + { + "id": "t_dining_gen_5", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.22, + "time": 60.39, + "distance": 1564.48, + "gen_feat_1": 491.41, + "gen_feat_2": 0.490673, + "gen_feat_3": 490.61 + } + }, + { + "id": "t_dining_gen_6", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.38, + "time": 58.67, + "distance": 1626.15, + "gen_feat_1": 488.5, + "gen_feat_2": 0.49348, + "gen_feat_3": 495.75 + } + }, + { + "id": "t_dining_gen_7", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.18, + "time": 60.72, + "distance": 1555.22, + "gen_feat_1": 505.8, + "gen_feat_2": 0.506719, + "gen_feat_3": 499.33 + } + }, + { + "id": "t_dining_gen_8", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.43, + "time": 59.64, + "distance": 1598.13, + "gen_feat_1": 503.89, + "gen_feat_2": 0.506945, + "gen_feat_3": 508.17 + } + }, + { + "id": "t_dining_gen_9", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.64, + "time": 60.54, + "distance": 1604.33, + "gen_feat_1": 486.84, + "gen_feat_2": 0.506628, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_dining_gen_10", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 60.17, + "distance": 1616.85, + "gen_feat_1": 507.44, + "gen_feat_2": 0.489997, + "gen_feat_3": 502.16 + } + }, + { + "id": "t_dining_gen_11", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.68, + "time": 59.16, + "distance": 1620.42, + "gen_feat_1": 507.98, + "gen_feat_2": 0.488942, + "gen_feat_3": 489.19 + } + }, + { + "id": "t_dining_gen_12", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.74, + "time": 59.04, + "distance": 1602.16, + "gen_feat_1": 504.58, + "gen_feat_2": 0.489389, + "gen_feat_3": 507.41 + } + }, + { + "id": "t_dining_gen_13", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.47, + "time": 58.89, + "distance": 1622.97, + "gen_feat_1": 492.31, + "gen_feat_2": 0.503154, + "gen_feat_3": 508.55 + } + }, + { + "id": "t_dining_gen_14", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.72, + "time": 58.91, + "distance": 1626.35, + "gen_feat_1": 509.41, + "gen_feat_2": 0.490291, + "gen_feat_3": 514.74 + } + }, + { + "id": "t_dining_gen_15", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.59, + "time": 60.67, + "distance": 1631.73, + "gen_feat_1": 493.43, + "gen_feat_2": 0.498961, + "gen_feat_3": 492.15 + } + }, + { + "id": "t_dining_gen_16", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.21, + "time": 59.57, + "distance": 1621.68, + "gen_feat_1": 502.04, + "gen_feat_2": 0.491944, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_dining_gen_17", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.33, + "time": 59.99, + "distance": 1602.82, + "gen_feat_1": 513.49, + "gen_feat_2": 0.510425, + "gen_feat_3": 506.46 + } + }, + { + "id": "t_dining_gen_18", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.02, + "time": 60.13, + "distance": 1639.2, + "gen_feat_1": 498.4, + "gen_feat_2": 0.499582, + "gen_feat_3": 504.62 + } + }, + { + "id": "t_dining_gen_19", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.03, + "time": 60.73, + "distance": 1642.13, + "gen_feat_1": 507.63, + "gen_feat_2": 0.500514, + "gen_feat_3": 495.73 + } + }, + { + "id": "t_dining_gen_20", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.33, + "time": 59.96, + "distance": 1568.96, + "gen_feat_1": 488.36, + "gen_feat_2": 0.514752, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_dining_gen_21", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.8, + "time": 58.42, + "distance": 1555.46, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486429, + "gen_feat_3": 488.41 + } + }, + { + "id": "t_dining_gen_22", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.66, + "time": 61.62, + "distance": 1580.67, + "gen_feat_1": 491.06, + "gen_feat_2": 0.506184, + "gen_feat_3": 501.23 + } + }, + { + "id": "t_dining_gen_23", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.42, + "time": 61.78, + "distance": 1622.72, + "gen_feat_1": 490.83, + "gen_feat_2": 0.489949, + "gen_feat_3": 487.73 + } + }, + { + "id": "t_dining_gen_24", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.71, + "time": 59.51, + "distance": 1580.85, + "gen_feat_1": 501.15, + "gen_feat_2": 0.50297, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_25", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.42, + "time": 61.41, + "distance": 1578.66, + "gen_feat_1": 507.39, + "gen_feat_2": 0.499268, + "gen_feat_3": 490.28 + } + }, + { + "id": "t_dining_gen_26", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.55, + "time": 58.26, + "distance": 1560.85, + "gen_feat_1": 492.17, + "gen_feat_2": 0.492399, + "gen_feat_3": 511.94 + } + }, + { + "id": "t_dining_gen_27", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.48, + "time": 58.34, + "distance": 1631.2, + "gen_feat_1": 498.39, + "gen_feat_2": 0.490821, + "gen_feat_3": 491.03 + } + }, + { + "id": "t_dining_gen_28", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.04, + "time": 61.28, + "distance": 1606.8, + "gen_feat_1": 512.73, + "gen_feat_2": 0.509267, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_dining_gen_29", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.76, + "time": 60.3, + "distance": 1569.61, + "gen_feat_1": 490.22, + "gen_feat_2": 0.496831, + "gen_feat_3": 496.53 + } + }, + { + "id": "t_dining_gen_30", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.71, + "time": 60.3, + "distance": 1623.3, + "gen_feat_1": 500.21, + "gen_feat_2": 0.496569, + "gen_feat_3": 498.99 + } + }, + { + "id": "t_dining_gen_31", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.86, + "time": 59.05, + "distance": 1588.58, + "gen_feat_1": 485.96, + "gen_feat_2": 0.512749, + "gen_feat_3": 498.55 + } + }, + { + "id": "t_dining_gen_32", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.8, + "time": 59.8, + "distance": 1560.3, + "gen_feat_1": 512.24, + "gen_feat_2": 0.486102, + "gen_feat_3": 508.8 + } + }, + { + "id": "t_dining_gen_33", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.49, + "time": 61.12, + "distance": 1612.82, + "gen_feat_1": 506.05, + "gen_feat_2": 0.504153, + "gen_feat_3": 510.28 + } + }, + { + "id": "t_dining_gen_34", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.66, + "time": 58.74, + "distance": 1627.51, + "gen_feat_1": 494.47, + "gen_feat_2": 0.509322, + "gen_feat_3": 485.53 + } + }, + { + "id": "t_dining_gen_35", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.14, + "time": 60.57, + "distance": 1626.08, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513739, + "gen_feat_3": 510.69 + } + }, + { + "id": "t_dining_gen_36", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.57, + "time": 58.38, + "distance": 1610.88, + "gen_feat_1": 495.23, + "gen_feat_2": 0.509726, + "gen_feat_3": 512.08 + } + }, + { + "id": "t_dining_gen_37", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.41, + "distance": 1575.46, + "gen_feat_1": 512.15, + "gen_feat_2": 0.492042, + "gen_feat_3": 505.13 + } + }, + { + "id": "t_dining_gen_38", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.22, + "time": 59.29, + "distance": 1557.64, + "gen_feat_1": 489.83, + "gen_feat_2": 0.49146, + "gen_feat_3": 495.3 + } + }, + { + "id": "t_dining_gen_39", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.59, + "time": 61.53, + "distance": 1562.65, + "gen_feat_1": 495.8, + "gen_feat_2": 0.496923, + "gen_feat_3": 507.91 + } + }, + { + "id": "t_dining_gen_40", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.43, + "time": 60.01, + "distance": 1604.0, + "gen_feat_1": 500.49, + "gen_feat_2": 0.514685, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_41", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.58, + "time": 60.72, + "distance": 1645.52, + "gen_feat_1": 487.19, + "gen_feat_2": 0.508959, + "gen_feat_3": 497.39 + } + }, + { + "id": "t_dining_gen_42", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.2, + "time": 59.26, + "distance": 1581.92, + "gen_feat_1": 509.7, + "gen_feat_2": 0.513201, + "gen_feat_3": 491.13 + } + }, + { + "id": "t_dining_gen_43", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.45, + "time": 60.26, + "distance": 1568.18, + "gen_feat_1": 493.86, + "gen_feat_2": 0.514555, + "gen_feat_3": 489.48 + } + }, + { + "id": "t_dining_gen_44", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.58, + "time": 58.5, + "distance": 1617.8, + "gen_feat_1": 491.08, + "gen_feat_2": 0.513671, + "gen_feat_3": 486.88 + } + }, + { + "id": "t_dining_gen_45", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.68, + "time": 61.23, + "distance": 1579.97, + "gen_feat_1": 509.82, + "gen_feat_2": 0.504088, + "gen_feat_3": 512.95 + } + }, + { + "id": "t_dining_gen_46", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 60.56, + "distance": 1641.45, + "gen_feat_1": 499.89, + "gen_feat_2": 0.510488, + "gen_feat_3": 491.3 + } + }, + { + "id": "t_dining_gen_47", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.94, + "time": 58.84, + "distance": 1629.37, + "gen_feat_1": 494.2, + "gen_feat_2": 0.49711, + "gen_feat_3": 496.8 + } + }, + { + "id": "t_dining_gen_48", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.23, + "time": 58.97, + "distance": 1607.14, + "gen_feat_1": 485.39, + "gen_feat_2": 0.485086, + "gen_feat_3": 504.57 + } + }, + { + "id": "t_dining_gen_49", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.47, + "time": 59.57, + "distance": 1615.57, + "gen_feat_1": 495.03, + "gen_feat_2": 0.503496, + "gen_feat_3": 509.51 + } + }, + { + "id": "t_dining_gen_50", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.7, + "distance": 1583.69, + "gen_feat_1": 489.31, + "gen_feat_2": 0.498993, + "gen_feat_3": 498.25 + } + }, + { + "id": "t_dining_gen_51", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.06, + "time": 60.11, + "distance": 1630.7, + "gen_feat_1": 507.83, + "gen_feat_2": 0.497927, + "gen_feat_3": 485.62 + } + }, + { + "id": "t_dining_gen_52", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.53, + "time": 58.59, + "distance": 1646.13, + "gen_feat_1": 489.54, + "gen_feat_2": 0.503777, + "gen_feat_3": 487.65 + } + }, + { + "id": "t_dining_gen_53", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.9, + "time": 58.5, + "distance": 1634.44, + "gen_feat_1": 514.43, + "gen_feat_2": 0.508093, + "gen_feat_3": 499.44 + } + }, + { + "id": "t_dining_gen_54", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.18, + "time": 58.68, + "distance": 1576.83, + "gen_feat_1": 491.93, + "gen_feat_2": 0.485409, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_dining_gen_55", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.0, + "distance": 1581.79, + "gen_feat_1": 489.92, + "gen_feat_2": 0.49016, + "gen_feat_3": 513.4 + } + }, + { + "id": "t_dining_gen_56", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.18, + "time": 61.73, + "distance": 1637.68, + "gen_feat_1": 492.48, + "gen_feat_2": 0.497966, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_dining_gen_57", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.2, + "time": 61.78, + "distance": 1646.08, + "gen_feat_1": 508.92, + "gen_feat_2": 0.500426, + "gen_feat_3": 499.7 + } + }, + { + "id": "t_dining_gen_58", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.57, + "time": 59.32, + "distance": 1580.58, + "gen_feat_1": 509.74, + "gen_feat_2": 0.510379, + "gen_feat_3": 512.86 + } + }, + { + "id": "t_dining_gen_59", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.54, + "time": 59.3, + "distance": 1570.05, + "gen_feat_1": 486.4, + "gen_feat_2": 0.503502, + "gen_feat_3": 498.65 + } + }, + { + "id": "t_dining_gen_60", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.18, + "time": 61.43, + "distance": 1636.11, + "gen_feat_1": 485.66, + "gen_feat_2": 0.498532, + "gen_feat_3": 506.32 + } + }, + { + "id": "t_dining_gen_61", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.01, + "time": 59.61, + "distance": 1626.73, + "gen_feat_1": 507.2, + "gen_feat_2": 0.505098, + "gen_feat_3": 499.85 + } + }, + { + "id": "t_dining_gen_62", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.22, + "time": 59.78, + "distance": 1646.36, + "gen_feat_1": 500.64, + "gen_feat_2": 0.500049, + "gen_feat_3": 504.88 + } + }, + { + "id": "t_dining_gen_63", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.11, + "time": 59.7, + "distance": 1621.52, + "gen_feat_1": 494.18, + "gen_feat_2": 0.498313, + "gen_feat_3": 506.17 + } + }, + { + "id": "t_dining_gen_64", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.71, + "time": 61.36, + "distance": 1568.12, + "gen_feat_1": 493.75, + "gen_feat_2": 0.505406, + "gen_feat_3": 512.82 + } + }, + { + "id": "t_dining_gen_65", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.4, + "time": 58.28, + "distance": 1604.89, + "gen_feat_1": 487.06, + "gen_feat_2": 0.502445, + "gen_feat_3": 511.12 + } + }, + { + "id": "t_dining_gen_66", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 59.57, + "distance": 1581.66, + "gen_feat_1": 513.25, + "gen_feat_2": 0.493068, + "gen_feat_3": 505.54 + } + }, + { + "id": "t_dining_gen_67", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.21, + "time": 60.81, + "distance": 1606.42, + "gen_feat_1": 493.36, + "gen_feat_2": 0.50459, + "gen_feat_3": 493.01 + } + }, + { + "id": "t_dining_gen_68", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 59.09, + "distance": 1611.43, + "gen_feat_1": 505.83, + "gen_feat_2": 0.502644, + "gen_feat_3": 504.4 + } + }, + { + "id": "t_dining_gen_69", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.92, + "time": 61.04, + "distance": 1579.9, + "gen_feat_1": 512.7, + "gen_feat_2": 0.488813, + "gen_feat_3": 500.85 + } + }, + { + "id": "t_dining_gen_70", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.74, + "time": 59.83, + "distance": 1615.86, + "gen_feat_1": 505.67, + "gen_feat_2": 0.48967, + "gen_feat_3": 503.59 + } + }, + { + "id": "t_dining_gen_71", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 61.74, + "distance": 1585.25, + "gen_feat_1": 495.74, + "gen_feat_2": 0.490106, + "gen_feat_3": 499.93 + } + }, + { + "id": "t_dining_gen_72", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.9, + "time": 58.61, + "distance": 1604.96, + "gen_feat_1": 509.49, + "gen_feat_2": 0.512456, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_73", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.41, + "time": 59.23, + "distance": 1631.69, + "gen_feat_1": 507.39, + "gen_feat_2": 0.504155, + "gen_feat_3": 514.37 + } + }, + { + "id": "t_dining_gen_74", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.5, + "time": 58.7, + "distance": 1628.56, + "gen_feat_1": 514.96, + "gen_feat_2": 0.498875, + "gen_feat_3": 512.16 + } + }, + { + "id": "t_dining_gen_75", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.83, + "time": 61.78, + "distance": 1589.19, + "gen_feat_1": 501.13, + "gen_feat_2": 0.504679, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_dining_gen_76", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.02, + "time": 61.78, + "distance": 1596.36, + "gen_feat_1": 511.57, + "gen_feat_2": 0.51185, + "gen_feat_3": 493.99 + } + }, + { + "id": "t_dining_gen_77", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.38, + "time": 59.52, + "distance": 1573.49, + "gen_feat_1": 513.61, + "gen_feat_2": 0.50886, + "gen_feat_3": 505.08 + } + }, + { + "id": "t_dining_gen_78", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.28, + "time": 59.03, + "distance": 1628.26, + "gen_feat_1": 513.77, + "gen_feat_2": 0.508209, + "gen_feat_3": 504.63 + } + }, + { + "id": "t_dining_gen_79", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.75, + "time": 60.98, + "distance": 1603.39, + "gen_feat_1": 510.74, + "gen_feat_2": 0.51442, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_dining_gen_80", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.34, + "time": 59.39, + "distance": 1607.15, + "gen_feat_1": 489.01, + "gen_feat_2": 0.508841, + "gen_feat_3": 503.65 + } + }, + { + "id": "t_dining_gen_81", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.78, + "time": 61.32, + "distance": 1606.79, + "gen_feat_1": 494.77, + "gen_feat_2": 0.498081, + "gen_feat_3": 490.68 + } + }, + { + "id": "t_dining_gen_82", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.0, + "time": 60.47, + "distance": 1578.03, + "gen_feat_1": 505.85, + "gen_feat_2": 0.496498, + "gen_feat_3": 494.3 + } + }, + { + "id": "t_dining_gen_83", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.59, + "time": 60.4, + "distance": 1576.41, + "gen_feat_1": 487.54, + "gen_feat_2": 0.490813, + "gen_feat_3": 506.97 + } + }, + { + "id": "t_dining_gen_84", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.45, + "time": 58.59, + "distance": 1635.41, + "gen_feat_1": 507.53, + "gen_feat_2": 0.499359, + "gen_feat_3": 511.49 + } + }, + { + "id": "t_dining_gen_85", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.55, + "time": 59.37, + "distance": 1578.95, + "gen_feat_1": 500.14, + "gen_feat_2": 0.504331, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_dining_gen_86", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.11, + "distance": 1556.1, + "gen_feat_1": 513.36, + "gen_feat_2": 0.512958, + "gen_feat_3": 493.44 + } + }, + { + "id": "t_dining_gen_87", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.26, + "time": 59.23, + "distance": 1563.62, + "gen_feat_1": 489.36, + "gen_feat_2": 0.51222, + "gen_feat_3": 503.86 + } + }, + { + "id": "t_dining_gen_88", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.46, + "time": 61.2, + "distance": 1588.14, + "gen_feat_1": 488.89, + "gen_feat_2": 0.496175, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_dining_gen_89", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.79, + "time": 58.63, + "distance": 1622.85, + "gen_feat_1": 512.62, + "gen_feat_2": 0.485995, + "gen_feat_3": 487.83 + } + }, + { + "id": "t_dining_gen_90", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.48, + "time": 58.69, + "distance": 1640.49, + "gen_feat_1": 511.37, + "gen_feat_2": 0.494218, + "gen_feat_3": 505.83 + } + }, + { + "id": "t_dining_gen_91", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.58, + "time": 58.72, + "distance": 1630.9, + "gen_feat_1": 505.33, + "gen_feat_2": 0.485446, + "gen_feat_3": 496.64 + } + }, + { + "id": "t_dining_gen_92", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.04, + "time": 59.56, + "distance": 1559.07, + "gen_feat_1": 491.21, + "gen_feat_2": 0.509726, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_93", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.84, + "time": 60.45, + "distance": 1596.68, + "gen_feat_1": 493.98, + "gen_feat_2": 0.489239, + "gen_feat_3": 493.56 + } + }, + { + "id": "t_dining_gen_94", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.56, + "time": 59.95, + "distance": 1630.28, + "gen_feat_1": 488.49, + "gen_feat_2": 0.505218, + "gen_feat_3": 491.42 + } + }, + { + "id": "t_dining_gen_95", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.97, + "time": 59.51, + "distance": 1593.3, + "gen_feat_1": 488.66, + "gen_feat_2": 0.490214, + "gen_feat_3": 504.25 + } + }, + { + "id": "t_dining_gen_96", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.85, + "time": 58.35, + "distance": 1552.26, + "gen_feat_1": 503.49, + "gen_feat_2": 0.48523, + "gen_feat_3": 504.39 + } + }, + { + "id": "t_dining_gen_97", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.51, + "time": 59.5, + "distance": 1634.44, + "gen_feat_1": 497.31, + "gen_feat_2": 0.5107, + "gen_feat_3": 507.86 + } + }, + { + "id": "t_dining_gen_98", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.5, + "time": 61.17, + "distance": 1593.89, + "gen_feat_1": 510.31, + "gen_feat_2": 0.50078, + "gen_feat_3": 494.95 + } + }, + { + "id": "t_shopping_gen_2", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.95, + "time": 44.3, + "distance": 1198.71, + "gen_feat_1": 508.4, + "gen_feat_2": 0.485625, + "gen_feat_3": 507.99 + } + }, + { + "id": "t_shopping_gen_3", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 44.18, + "distance": 1196.21, + "gen_feat_1": 485.72, + "gen_feat_2": 0.488455, + "gen_feat_3": 489.7 + } + }, + { + "id": "t_shopping_gen_4", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.78, + "time": 44.9, + "distance": 1179.12, + "gen_feat_1": 503.26, + "gen_feat_2": 0.498291, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_shopping_gen_5", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.51, + "time": 44.53, + "distance": 1216.23, + "gen_feat_1": 510.8, + "gen_feat_2": 0.507066, + "gen_feat_3": 504.03 + } + }, + { + "id": "t_shopping_gen_6", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.18, + "time": 44.06, + "distance": 1199.34, + "gen_feat_1": 501.17, + "gen_feat_2": 0.493458, + "gen_feat_3": 510.83 + } + }, + { + "id": "t_shopping_gen_7", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.59, + "time": 45.0, + "distance": 1183.14, + "gen_feat_1": 501.56, + "gen_feat_2": 0.496232, + "gen_feat_3": 496.33 + } + }, + { + "id": "t_shopping_gen_8", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.45, + "time": 43.75, + "distance": 1196.19, + "gen_feat_1": 488.54, + "gen_feat_2": 0.508864, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_9", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.29, + "time": 45.49, + "distance": 1235.6, + "gen_feat_1": 505.19, + "gen_feat_2": 0.486447, + "gen_feat_3": 505.3 + } + }, + { + "id": "t_shopping_gen_10", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.2, + "time": 44.86, + "distance": 1227.31, + "gen_feat_1": 487.19, + "gen_feat_2": 0.512416, + "gen_feat_3": 499.73 + } + }, + { + "id": "t_shopping_gen_11", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.86, + "time": 44.51, + "distance": 1227.77, + "gen_feat_1": 488.24, + "gen_feat_2": 0.510589, + "gen_feat_3": 510.74 + } + }, + { + "id": "t_shopping_gen_12", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.87, + "time": 44.69, + "distance": 1170.61, + "gen_feat_1": 503.79, + "gen_feat_2": 0.487994, + "gen_feat_3": 485.28 + } + }, + { + "id": "t_shopping_gen_13", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.87, + "time": 46.21, + "distance": 1228.85, + "gen_feat_1": 488.6, + "gen_feat_2": 0.499239, + "gen_feat_3": 503.2 + } + }, + { + "id": "t_shopping_gen_14", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.47, + "time": 44.09, + "distance": 1191.47, + "gen_feat_1": 510.69, + "gen_feat_2": 0.500607, + "gen_feat_3": 501.94 + } + }, + { + "id": "t_shopping_gen_15", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.91, + "time": 44.79, + "distance": 1194.44, + "gen_feat_1": 493.04, + "gen_feat_2": 0.493381, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_16", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.74, + "time": 45.76, + "distance": 1214.32, + "gen_feat_1": 508.04, + "gen_feat_2": 0.505849, + "gen_feat_3": 514.42 + } + }, + { + "id": "t_shopping_gen_17", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.56, + "time": 44.53, + "distance": 1186.46, + "gen_feat_1": 497.1, + "gen_feat_2": 0.507483, + "gen_feat_3": 487.33 + } + }, + { + "id": "t_shopping_gen_18", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.3, + "time": 46.02, + "distance": 1191.93, + "gen_feat_1": 502.5, + "gen_feat_2": 0.489832, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_shopping_gen_19", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.29, + "time": 44.76, + "distance": 1178.65, + "gen_feat_1": 486.31, + "gen_feat_2": 0.501927, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_shopping_gen_20", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.59, + "time": 45.62, + "distance": 1234.59, + "gen_feat_1": 508.23, + "gen_feat_2": 0.488622, + "gen_feat_3": 505.15 + } + }, + { + "id": "t_shopping_gen_21", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.41, + "time": 44.06, + "distance": 1185.1, + "gen_feat_1": 498.37, + "gen_feat_2": 0.491076, + "gen_feat_3": 502.07 + } + }, + { + "id": "t_shopping_gen_22", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.07, + "time": 45.23, + "distance": 1172.35, + "gen_feat_1": 489.15, + "gen_feat_2": 0.487341, + "gen_feat_3": 502.22 + } + }, + { + "id": "t_shopping_gen_23", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.07, + "time": 44.11, + "distance": 1228.63, + "gen_feat_1": 489.68, + "gen_feat_2": 0.497214, + "gen_feat_3": 510.3 + } + }, + { + "id": "t_shopping_gen_24", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.79, + "time": 45.29, + "distance": 1211.47, + "gen_feat_1": 513.99, + "gen_feat_2": 0.511272, + "gen_feat_3": 512.18 + } + }, + { + "id": "t_shopping_gen_25", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.49, + "time": 45.68, + "distance": 1197.16, + "gen_feat_1": 504.19, + "gen_feat_2": 0.507954, + "gen_feat_3": 509.7 + } + }, + { + "id": "t_shopping_gen_26", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.61, + "time": 45.73, + "distance": 1191.91, + "gen_feat_1": 499.13, + "gen_feat_2": 0.502797, + "gen_feat_3": 486.18 + } + }, + { + "id": "t_shopping_gen_27", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.64, + "time": 45.28, + "distance": 1176.71, + "gen_feat_1": 505.64, + "gen_feat_2": 0.491227, + "gen_feat_3": 508.35 + } + }, + { + "id": "t_shopping_gen_28", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.87, + "time": 45.0, + "distance": 1216.17, + "gen_feat_1": 500.61, + "gen_feat_2": 0.512609, + "gen_feat_3": 509.87 + } + }, + { + "id": "t_shopping_gen_29", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.37, + "time": 44.26, + "distance": 1180.24, + "gen_feat_1": 487.72, + "gen_feat_2": 0.485295, + "gen_feat_3": 487.2 + } + }, + { + "id": "t_shopping_gen_30", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.65, + "time": 44.57, + "distance": 1197.12, + "gen_feat_1": 500.2, + "gen_feat_2": 0.506494, + "gen_feat_3": 511.02 + } + }, + { + "id": "t_shopping_gen_31", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.54, + "time": 43.79, + "distance": 1190.28, + "gen_feat_1": 501.09, + "gen_feat_2": 0.496883, + "gen_feat_3": 504.0 + } + }, + { + "id": "t_shopping_gen_32", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.4, + "time": 44.15, + "distance": 1210.36, + "gen_feat_1": 506.65, + "gen_feat_2": 0.494619, + "gen_feat_3": 489.54 + } + }, + { + "id": "t_shopping_gen_33", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.78, + "time": 44.05, + "distance": 1224.7, + "gen_feat_1": 505.11, + "gen_feat_2": 0.497586, + "gen_feat_3": 502.56 + } + }, + { + "id": "t_shopping_gen_34", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.93, + "time": 45.15, + "distance": 1219.85, + "gen_feat_1": 498.34, + "gen_feat_2": 0.488983, + "gen_feat_3": 494.13 + } + }, + { + "id": "t_shopping_gen_35", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.82, + "time": 44.55, + "distance": 1224.73, + "gen_feat_1": 511.51, + "gen_feat_2": 0.504196, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_shopping_gen_36", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.86, + "time": 45.5, + "distance": 1196.08, + "gen_feat_1": 495.33, + "gen_feat_2": 0.498326, + "gen_feat_3": 486.34 + } + }, + { + "id": "t_shopping_gen_37", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.59, + "time": 44.26, + "distance": 1203.59, + "gen_feat_1": 496.81, + "gen_feat_2": 0.510331, + "gen_feat_3": 506.27 + } + }, + { + "id": "t_shopping_gen_38", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.92, + "time": 45.08, + "distance": 1203.94, + "gen_feat_1": 500.75, + "gen_feat_2": 0.49117, + "gen_feat_3": 491.78 + } + }, + { + "id": "t_shopping_gen_39", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.31, + "time": 46.16, + "distance": 1182.79, + "gen_feat_1": 497.1, + "gen_feat_2": 0.497946, + "gen_feat_3": 512.02 + } + }, + { + "id": "t_shopping_gen_40", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.54, + "time": 44.22, + "distance": 1217.58, + "gen_feat_1": 514.19, + "gen_feat_2": 0.507653, + "gen_feat_3": 502.34 + } + }, + { + "id": "t_shopping_gen_41", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.64, + "time": 44.32, + "distance": 1196.64, + "gen_feat_1": 510.6, + "gen_feat_2": 0.510227, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_42", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.93, + "time": 46.08, + "distance": 1215.22, + "gen_feat_1": 509.33, + "gen_feat_2": 0.489128, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_43", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.94, + "time": 46.06, + "distance": 1197.83, + "gen_feat_1": 494.23, + "gen_feat_2": 0.491429, + "gen_feat_3": 512.77 + } + }, + { + "id": "t_shopping_gen_44", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.62, + "time": 44.6, + "distance": 1228.92, + "gen_feat_1": 503.07, + "gen_feat_2": 0.497061, + "gen_feat_3": 508.73 + } + }, + { + "id": "t_shopping_gen_45", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.54, + "time": 45.8, + "distance": 1230.3, + "gen_feat_1": 498.44, + "gen_feat_2": 0.491182, + "gen_feat_3": 510.12 + } + }, + { + "id": "t_shopping_gen_46", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 44.28, + "distance": 1216.64, + "gen_feat_1": 488.95, + "gen_feat_2": 0.485686, + "gen_feat_3": 513.45 + } + }, + { + "id": "t_shopping_gen_47", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.4, + "time": 44.8, + "distance": 1210.54, + "gen_feat_1": 488.83, + "gen_feat_2": 0.508023, + "gen_feat_3": 485.22 + } + }, + { + "id": "t_shopping_gen_48", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.69, + "time": 44.94, + "distance": 1204.74, + "gen_feat_1": 504.02, + "gen_feat_2": 0.485166, + "gen_feat_3": 509.28 + } + }, + { + "id": "t_shopping_gen_49", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.63, + "time": 45.76, + "distance": 1234.29, + "gen_feat_1": 496.66, + "gen_feat_2": 0.510271, + "gen_feat_3": 488.57 + } + }, + { + "id": "t_shopping_gen_50", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.54, + "time": 44.91, + "distance": 1215.96, + "gen_feat_1": 509.77, + "gen_feat_2": 0.485673, + "gen_feat_3": 502.33 + } + }, + { + "id": "t_shopping_gen_51", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.48, + "time": 46.17, + "distance": 1186.08, + "gen_feat_1": 512.11, + "gen_feat_2": 0.491803, + "gen_feat_3": 503.47 + } + }, + { + "id": "t_shopping_gen_52", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.89, + "time": 44.45, + "distance": 1194.92, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486916, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_shopping_gen_53", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.35, + "time": 44.61, + "distance": 1191.25, + "gen_feat_1": 503.61, + "gen_feat_2": 0.493221, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_shopping_gen_54", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.73, + "time": 45.54, + "distance": 1223.55, + "gen_feat_1": 494.27, + "gen_feat_2": 0.490001, + "gen_feat_3": 493.72 + } + }, + { + "id": "t_shopping_gen_55", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 44.24, + "distance": 1228.06, + "gen_feat_1": 497.25, + "gen_feat_2": 0.49955, + "gen_feat_3": 486.14 + } + }, + { + "id": "t_shopping_gen_56", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.69, + "time": 44.04, + "distance": 1224.5, + "gen_feat_1": 492.29, + "gen_feat_2": 0.500032, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_57", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.68, + "time": 46.32, + "distance": 1227.05, + "gen_feat_1": 510.63, + "gen_feat_2": 0.51217, + "gen_feat_3": 489.8 + } + }, + { + "id": "t_shopping_gen_58", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.13, + "time": 45.42, + "distance": 1231.38, + "gen_feat_1": 499.25, + "gen_feat_2": 0.502657, + "gen_feat_3": 488.16 + } + }, + { + "id": "t_shopping_gen_59", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 45.04, + "distance": 1206.58, + "gen_feat_1": 488.66, + "gen_feat_2": 0.500622, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_shopping_gen_60", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.33, + "time": 46.0, + "distance": 1170.11, + "gen_feat_1": 511.4, + "gen_feat_2": 0.49549, + "gen_feat_3": 503.71 + } + }, + { + "id": "t_shopping_gen_61", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.18, + "time": 46.1, + "distance": 1190.97, + "gen_feat_1": 498.6, + "gen_feat_2": 0.501812, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_62", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.24, + "time": 45.7, + "distance": 1164.26, + "gen_feat_1": 485.26, + "gen_feat_2": 0.49031, + "gen_feat_3": 487.45 + } + }, + { + "id": "t_shopping_gen_63", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.17, + "time": 45.97, + "distance": 1190.2, + "gen_feat_1": 511.28, + "gen_feat_2": 0.51432, + "gen_feat_3": 513.58 + } + }, + { + "id": "t_shopping_gen_64", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.73, + "time": 44.03, + "distance": 1178.97, + "gen_feat_1": 487.49, + "gen_feat_2": 0.508632, + "gen_feat_3": 500.21 + } + }, + { + "id": "t_shopping_gen_65", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.67, + "time": 43.83, + "distance": 1176.27, + "gen_feat_1": 512.03, + "gen_feat_2": 0.49815, + "gen_feat_3": 501.03 + } + }, + { + "id": "t_shopping_gen_66", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.26, + "time": 44.73, + "distance": 1220.07, + "gen_feat_1": 504.64, + "gen_feat_2": 0.502789, + "gen_feat_3": 505.95 + } + }, + { + "id": "t_shopping_gen_67", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.81, + "time": 44.73, + "distance": 1180.99, + "gen_feat_1": 491.13, + "gen_feat_2": 0.488945, + "gen_feat_3": 487.4 + } + }, + { + "id": "t_shopping_gen_68", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.86, + "time": 43.67, + "distance": 1232.56, + "gen_feat_1": 512.67, + "gen_feat_2": 0.491258, + "gen_feat_3": 495.53 + } + }, + { + "id": "t_shopping_gen_69", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.0, + "time": 45.32, + "distance": 1179.79, + "gen_feat_1": 504.7, + "gen_feat_2": 0.501825, + "gen_feat_3": 494.35 + } + }, + { + "id": "t_shopping_gen_70", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 45.99, + "distance": 1206.39, + "gen_feat_1": 497.84, + "gen_feat_2": 0.509326, + "gen_feat_3": 508.37 + } + }, + { + "id": "t_shopping_gen_71", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.89, + "time": 44.23, + "distance": 1211.83, + "gen_feat_1": 489.02, + "gen_feat_2": 0.504569, + "gen_feat_3": 486.74 + } + }, + { + "id": "t_shopping_gen_72", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.25, + "time": 43.89, + "distance": 1218.83, + "gen_feat_1": 514.57, + "gen_feat_2": 0.487312, + "gen_feat_3": 491.96 + } + }, + { + "id": "t_shopping_gen_73", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 45.64, + "distance": 1171.76, + "gen_feat_1": 499.58, + "gen_feat_2": 0.499353, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_shopping_gen_74", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.51, + "time": 45.18, + "distance": 1235.16, + "gen_feat_1": 491.35, + "gen_feat_2": 0.488032, + "gen_feat_3": 508.76 + } + }, + { + "id": "t_shopping_gen_75", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.45, + "time": 45.29, + "distance": 1185.87, + "gen_feat_1": 506.16, + "gen_feat_2": 0.494622, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_shopping_gen_76", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.11, + "time": 44.39, + "distance": 1222.53, + "gen_feat_1": 507.53, + "gen_feat_2": 0.505002, + "gen_feat_3": 503.01 + } + }, + { + "id": "t_shopping_gen_77", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.93, + "time": 46.13, + "distance": 1210.75, + "gen_feat_1": 506.27, + "gen_feat_2": 0.505682, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_shopping_gen_78", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.16, + "time": 46.07, + "distance": 1210.7, + "gen_feat_1": 508.56, + "gen_feat_2": 0.487189, + "gen_feat_3": 504.12 + } + }, + { + "id": "t_shopping_gen_79", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.03, + "time": 45.66, + "distance": 1190.96, + "gen_feat_1": 489.72, + "gen_feat_2": 0.488214, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_shopping_gen_80", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.77, + "time": 45.73, + "distance": 1226.46, + "gen_feat_1": 498.85, + "gen_feat_2": 0.50612, + "gen_feat_3": 508.83 + } + }, + { + "id": "t_shopping_gen_81", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.19, + "time": 44.4, + "distance": 1207.41, + "gen_feat_1": 512.69, + "gen_feat_2": 0.49773, + "gen_feat_3": 499.57 + } + }, + { + "id": "t_shopping_gen_82", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.91, + "time": 45.81, + "distance": 1232.14, + "gen_feat_1": 501.37, + "gen_feat_2": 0.501413, + "gen_feat_3": 509.02 + } + }, + { + "id": "t_shopping_gen_83", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.46, + "time": 45.7, + "distance": 1201.06, + "gen_feat_1": 507.37, + "gen_feat_2": 0.512514, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_84", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.46, + "time": 45.7, + "distance": 1176.63, + "gen_feat_1": 500.57, + "gen_feat_2": 0.512907, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_shopping_gen_85", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.3, + "time": 44.77, + "distance": 1227.54, + "gen_feat_1": 488.72, + "gen_feat_2": 0.491267, + "gen_feat_3": 504.72 + } + }, + { + "id": "t_shopping_gen_86", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.53, + "time": 44.82, + "distance": 1227.19, + "gen_feat_1": 495.19, + "gen_feat_2": 0.506807, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_shopping_gen_87", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.76, + "time": 45.19, + "distance": 1197.27, + "gen_feat_1": 492.23, + "gen_feat_2": 0.502276, + "gen_feat_3": 497.83 + } + }, + { + "id": "t_shopping_gen_88", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.51, + "time": 46.32, + "distance": 1202.27, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500008, + "gen_feat_3": 494.37 + } + }, + { + "id": "t_shopping_gen_89", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.31, + "time": 45.09, + "distance": 1196.05, + "gen_feat_1": 488.52, + "gen_feat_2": 0.501783, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_90", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.15, + "time": 45.09, + "distance": 1187.36, + "gen_feat_1": 510.87, + "gen_feat_2": 0.48952, + "gen_feat_3": 487.44 + } + }, + { + "id": "t_shopping_gen_91", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.98, + "time": 44.28, + "distance": 1230.46, + "gen_feat_1": 494.85, + "gen_feat_2": 0.49072, + "gen_feat_3": 507.33 + } + }, + { + "id": "t_shopping_gen_92", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.46, + "time": 44.78, + "distance": 1190.65, + "gen_feat_1": 511.14, + "gen_feat_2": 0.491965, + "gen_feat_3": 510.07 + } + }, + { + "id": "t_shopping_gen_93", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 44.16, + "distance": 1232.76, + "gen_feat_1": 491.76, + "gen_feat_2": 0.49386, + "gen_feat_3": 489.99 + } + }, + { + "id": "t_shopping_gen_94", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.09, + "time": 45.07, + "distance": 1187.9, + "gen_feat_1": 500.36, + "gen_feat_2": 0.505173, + "gen_feat_3": 512.28 + } + }, + { + "id": "t_shopping_gen_95", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.29, + "time": 44.73, + "distance": 1224.17, + "gen_feat_1": 507.58, + "gen_feat_2": 0.48708, + "gen_feat_3": 511.59 + } + }, + { + "id": "t_shopping_gen_96", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.53, + "time": 43.89, + "distance": 1206.53, + "gen_feat_1": 493.71, + "gen_feat_2": 0.505153, + "gen_feat_3": 502.61 + } + }, + { + "id": "t_shopping_gen_97", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.6, + "time": 45.25, + "distance": 1198.77, + "gen_feat_1": 499.74, + "gen_feat_2": 0.499805, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_shopping_gen_98", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.94, + "time": 45.61, + "distance": 1168.51, + "gen_feat_1": 491.6, + "gen_feat_2": 0.511011, + "gen_feat_3": 491.45 + } + }, + { + "id": "t_shopping_gen_99", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.76, + "time": 45.99, + "distance": 1192.67, + "gen_feat_1": 500.07, + "gen_feat_2": 0.491787, + "gen_feat_3": 488.2 + } + }, + { + "id": "t_movie_gen_2", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.81, + "time": 138.02, + "distance": 1654.01, + "gen_feat_1": 503.91, + "gen_feat_2": 0.502664, + "gen_feat_3": 506.8 + } + }, + { + "id": "t_movie_gen_3", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.98, + "time": 133.32, + "distance": 1664.29, + "gen_feat_1": 491.47, + "gen_feat_2": 0.500325, + "gen_feat_3": 496.28 + } + }, + { + "id": "t_movie_gen_4", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.11, + "time": 136.06, + "distance": 1704.88, + "gen_feat_1": 505.19, + "gen_feat_2": 0.509953, + "gen_feat_3": 499.19 + } + }, + { + "id": "t_movie_gen_5", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.17, + "time": 136.4, + "distance": 1724.13, + "gen_feat_1": 511.77, + "gen_feat_2": 0.505076, + "gen_feat_3": 491.0 + } + }, + { + "id": "t_movie_gen_6", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.2, + "time": 137.15, + "distance": 1664.63, + "gen_feat_1": 514.48, + "gen_feat_2": 0.503771, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_movie_gen_7", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.16, + "time": 135.61, + "distance": 1726.58, + "gen_feat_1": 493.34, + "gen_feat_2": 0.493128, + "gen_feat_3": 491.4 + } + }, + { + "id": "t_movie_gen_8", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.91, + "time": 135.69, + "distance": 1678.5, + "gen_feat_1": 493.49, + "gen_feat_2": 0.506584, + "gen_feat_3": 491.95 + } + }, + { + "id": "t_movie_gen_9", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.09, + "time": 132.47, + "distance": 1682.74, + "gen_feat_1": 513.37, + "gen_feat_2": 0.496243, + "gen_feat_3": 510.52 + } + }, + { + "id": "t_movie_gen_10", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.25, + "time": 134.94, + "distance": 1683.72, + "gen_feat_1": 493.66, + "gen_feat_2": 0.502149, + "gen_feat_3": 491.38 + } + }, + { + "id": "t_movie_gen_11", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 132.2, + "distance": 1677.4, + "gen_feat_1": 513.51, + "gen_feat_2": 0.512663, + "gen_feat_3": 496.77 + } + }, + { + "id": "t_movie_gen_12", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.02, + "time": 136.12, + "distance": 1683.25, + "gen_feat_1": 486.72, + "gen_feat_2": 0.48763, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_movie_gen_13", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 131.91, + "distance": 1710.85, + "gen_feat_1": 493.33, + "gen_feat_2": 0.499006, + "gen_feat_3": 497.58 + } + }, + { + "id": "t_movie_gen_14", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.85, + "time": 137.69, + "distance": 1738.0, + "gen_feat_1": 501.65, + "gen_feat_2": 0.507629, + "gen_feat_3": 509.86 + } + }, + { + "id": "t_movie_gen_15", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.02, + "time": 133.61, + "distance": 1660.2, + "gen_feat_1": 512.64, + "gen_feat_2": 0.487548, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_movie_gen_16", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.2, + "time": 132.6, + "distance": 1669.36, + "gen_feat_1": 490.54, + "gen_feat_2": 0.507088, + "gen_feat_3": 496.37 + } + }, + { + "id": "t_movie_gen_17", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.25, + "time": 138.2, + "distance": 1711.42, + "gen_feat_1": 497.15, + "gen_feat_2": 0.513509, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_movie_gen_18", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.76, + "time": 136.31, + "distance": 1749.75, + "gen_feat_1": 514.83, + "gen_feat_2": 0.50335, + "gen_feat_3": 503.33 + } + }, + { + "id": "t_movie_gen_19", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 131.68, + "distance": 1656.52, + "gen_feat_1": 487.37, + "gen_feat_2": 0.493627, + "gen_feat_3": 508.19 + } + }, + { + "id": "t_movie_gen_20", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.9, + "time": 137.27, + "distance": 1709.53, + "gen_feat_1": 497.44, + "gen_feat_2": 0.486038, + "gen_feat_3": 502.32 + } + }, + { + "id": "t_movie_gen_21", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.83, + "time": 136.88, + "distance": 1708.94, + "gen_feat_1": 492.6, + "gen_feat_2": 0.496495, + "gen_feat_3": 490.83 + } + }, + { + "id": "t_movie_gen_22", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.12, + "time": 133.07, + "distance": 1711.62, + "gen_feat_1": 493.34, + "gen_feat_2": 0.499182, + "gen_feat_3": 499.28 + } + }, + { + "id": "t_movie_gen_23", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.12, + "time": 134.21, + "distance": 1736.25, + "gen_feat_1": 503.64, + "gen_feat_2": 0.5068, + "gen_feat_3": 489.21 + } + }, + { + "id": "t_movie_gen_24", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 132.64, + "distance": 1664.88, + "gen_feat_1": 510.09, + "gen_feat_2": 0.510289, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_movie_gen_25", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.1, + "time": 137.12, + "distance": 1701.34, + "gen_feat_1": 501.06, + "gen_feat_2": 0.49893, + "gen_feat_3": 507.73 + } + }, + { + "id": "t_movie_gen_26", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 136.45, + "distance": 1678.04, + "gen_feat_1": 494.8, + "gen_feat_2": 0.485118, + "gen_feat_3": 508.86 + } + }, + { + "id": "t_movie_gen_27", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.83, + "time": 134.67, + "distance": 1694.92, + "gen_feat_1": 503.64, + "gen_feat_2": 0.511029, + "gen_feat_3": 505.48 + } + }, + { + "id": "t_movie_gen_28", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.96, + "time": 138.62, + "distance": 1659.13, + "gen_feat_1": 491.47, + "gen_feat_2": 0.511429, + "gen_feat_3": 500.08 + } + }, + { + "id": "t_movie_gen_29", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.76, + "time": 138.64, + "distance": 1697.07, + "gen_feat_1": 498.44, + "gen_feat_2": 0.509025, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_movie_gen_30", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.39, + "distance": 1730.3, + "gen_feat_1": 510.02, + "gen_feat_2": 0.491101, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_31", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.28, + "time": 131.41, + "distance": 1685.65, + "gen_feat_1": 490.64, + "gen_feat_2": 0.485642, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_movie_gen_32", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.93, + "time": 134.98, + "distance": 1695.11, + "gen_feat_1": 501.21, + "gen_feat_2": 0.50543, + "gen_feat_3": 499.51 + } + }, + { + "id": "t_movie_gen_33", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.87, + "time": 137.83, + "distance": 1715.38, + "gen_feat_1": 513.71, + "gen_feat_2": 0.493568, + "gen_feat_3": 514.01 + } + }, + { + "id": "t_movie_gen_34", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.81, + "time": 132.4, + "distance": 1663.09, + "gen_feat_1": 506.91, + "gen_feat_2": 0.510638, + "gen_feat_3": 501.83 + } + }, + { + "id": "t_movie_gen_35", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.24, + "time": 136.79, + "distance": 1694.27, + "gen_feat_1": 510.84, + "gen_feat_2": 0.507452, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_movie_gen_36", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.16, + "time": 136.15, + "distance": 1670.24, + "gen_feat_1": 502.99, + "gen_feat_2": 0.495856, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_37", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.3, + "time": 136.48, + "distance": 1719.06, + "gen_feat_1": 512.77, + "gen_feat_2": 0.488773, + "gen_feat_3": 505.19 + } + }, + { + "id": "t_movie_gen_38", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.89, + "time": 137.8, + "distance": 1682.43, + "gen_feat_1": 514.67, + "gen_feat_2": 0.508214, + "gen_feat_3": 504.71 + } + }, + { + "id": "t_movie_gen_39", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.88, + "time": 136.94, + "distance": 1652.85, + "gen_feat_1": 499.19, + "gen_feat_2": 0.500729, + "gen_feat_3": 511.08 + } + }, + { + "id": "t_movie_gen_40", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.75, + "time": 136.81, + "distance": 1673.83, + "gen_feat_1": 510.5, + "gen_feat_2": 0.496266, + "gen_feat_3": 512.35 + } + }, + { + "id": "t_movie_gen_41", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.84, + "time": 133.13, + "distance": 1698.79, + "gen_feat_1": 504.79, + "gen_feat_2": 0.491761, + "gen_feat_3": 489.88 + } + }, + { + "id": "t_movie_gen_42", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.79, + "time": 132.71, + "distance": 1654.02, + "gen_feat_1": 488.54, + "gen_feat_2": 0.496646, + "gen_feat_3": 506.89 + } + }, + { + "id": "t_movie_gen_43", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.03, + "time": 135.73, + "distance": 1687.52, + "gen_feat_1": 489.12, + "gen_feat_2": 0.50799, + "gen_feat_3": 499.94 + } + }, + { + "id": "t_movie_gen_44", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.09, + "time": 138.68, + "distance": 1703.05, + "gen_feat_1": 510.12, + "gen_feat_2": 0.485551, + "gen_feat_3": 502.13 + } + }, + { + "id": "t_movie_gen_45", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.86, + "time": 133.42, + "distance": 1652.65, + "gen_feat_1": 488.6, + "gen_feat_2": 0.510397, + "gen_feat_3": 509.98 + } + }, + { + "id": "t_movie_gen_46", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.97, + "time": 131.94, + "distance": 1673.56, + "gen_feat_1": 486.56, + "gen_feat_2": 0.505523, + "gen_feat_3": 501.82 + } + }, + { + "id": "t_movie_gen_47", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.0, + "time": 133.55, + "distance": 1671.34, + "gen_feat_1": 488.32, + "gen_feat_2": 0.49915, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_movie_gen_48", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.06, + "time": 138.36, + "distance": 1677.66, + "gen_feat_1": 497.58, + "gen_feat_2": 0.497849, + "gen_feat_3": 488.29 + } + }, + { + "id": "t_movie_gen_49", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 133.95, + "distance": 1742.48, + "gen_feat_1": 495.5, + "gen_feat_2": 0.511503, + "gen_feat_3": 491.31 + } + }, + { + "id": "t_movie_gen_50", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.77, + "time": 135.54, + "distance": 1710.41, + "gen_feat_1": 487.97, + "gen_feat_2": 0.508317, + "gen_feat_3": 490.49 + } + }, + { + "id": "t_movie_gen_51", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.77, + "time": 135.9, + "distance": 1664.29, + "gen_feat_1": 513.14, + "gen_feat_2": 0.507714, + "gen_feat_3": 487.99 + } + }, + { + "id": "t_movie_gen_52", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.74, + "time": 133.36, + "distance": 1679.04, + "gen_feat_1": 502.14, + "gen_feat_2": 0.489374, + "gen_feat_3": 501.0 + } + }, + { + "id": "t_movie_gen_53", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.75, + "time": 137.75, + "distance": 1727.9, + "gen_feat_1": 494.43, + "gen_feat_2": 0.492795, + "gen_feat_3": 507.56 + } + }, + { + "id": "t_movie_gen_54", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 137.23, + "distance": 1749.88, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514964, + "gen_feat_3": 513.51 + } + }, + { + "id": "t_movie_gen_55", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.27, + "time": 131.7, + "distance": 1671.69, + "gen_feat_1": 491.71, + "gen_feat_2": 0.507637, + "gen_feat_3": 496.63 + } + }, + { + "id": "t_movie_gen_56", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.25, + "time": 133.82, + "distance": 1744.69, + "gen_feat_1": 513.96, + "gen_feat_2": 0.486719, + "gen_feat_3": 505.59 + } + }, + { + "id": "t_movie_gen_57", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.99, + "distance": 1687.02, + "gen_feat_1": 495.73, + "gen_feat_2": 0.497053, + "gen_feat_3": 485.08 + } + }, + { + "id": "t_movie_gen_58", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 134.0, + "distance": 1717.93, + "gen_feat_1": 498.58, + "gen_feat_2": 0.514512, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_movie_gen_59", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 135.99, + "distance": 1669.61, + "gen_feat_1": 506.91, + "gen_feat_2": 0.486343, + "gen_feat_3": 513.29 + } + }, + { + "id": "t_movie_gen_60", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 137.16, + "distance": 1727.65, + "gen_feat_1": 511.78, + "gen_feat_2": 0.498191, + "gen_feat_3": 495.09 + } + }, + { + "id": "t_movie_gen_61", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.06, + "time": 131.51, + "distance": 1688.72, + "gen_feat_1": 501.65, + "gen_feat_2": 0.503774, + "gen_feat_3": 494.98 + } + }, + { + "id": "t_movie_gen_62", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 134.94, + "distance": 1688.34, + "gen_feat_1": 486.17, + "gen_feat_2": 0.506252, + "gen_feat_3": 499.8 + } + }, + { + "id": "t_movie_gen_63", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.0, + "time": 132.52, + "distance": 1696.65, + "gen_feat_1": 514.69, + "gen_feat_2": 0.493209, + "gen_feat_3": 485.24 + } + }, + { + "id": "t_movie_gen_64", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.73, + "time": 131.33, + "distance": 1699.32, + "gen_feat_1": 494.73, + "gen_feat_2": 0.500638, + "gen_feat_3": 507.36 + } + }, + { + "id": "t_movie_gen_65", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.28, + "time": 135.57, + "distance": 1672.37, + "gen_feat_1": 512.61, + "gen_feat_2": 0.49003, + "gen_feat_3": 498.67 + } + }, + { + "id": "t_movie_gen_66", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.81, + "time": 133.8, + "distance": 1700.55, + "gen_feat_1": 512.0, + "gen_feat_2": 0.486179, + "gen_feat_3": 501.33 + } + }, + { + "id": "t_movie_gen_67", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.03, + "time": 131.77, + "distance": 1745.74, + "gen_feat_1": 503.3, + "gen_feat_2": 0.51441, + "gen_feat_3": 486.9 + } + }, + { + "id": "t_movie_gen_68", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.9, + "time": 137.31, + "distance": 1655.07, + "gen_feat_1": 485.6, + "gen_feat_2": 0.49856, + "gen_feat_3": 495.04 + } + }, + { + "id": "t_movie_gen_69", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.19, + "time": 137.9, + "distance": 1713.23, + "gen_feat_1": 510.23, + "gen_feat_2": 0.490473, + "gen_feat_3": 492.48 + } + }, + { + "id": "t_movie_gen_70", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.92, + "time": 137.74, + "distance": 1742.03, + "gen_feat_1": 497.94, + "gen_feat_2": 0.514756, + "gen_feat_3": 487.31 + } + }, + { + "id": "t_movie_gen_71", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.28, + "time": 134.06, + "distance": 1654.96, + "gen_feat_1": 510.56, + "gen_feat_2": 0.492021, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_movie_gen_72", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 135.82, + "distance": 1738.49, + "gen_feat_1": 500.42, + "gen_feat_2": 0.493135, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_73", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 134.69, + "distance": 1663.19, + "gen_feat_1": 491.2, + "gen_feat_2": 0.505794, + "gen_feat_3": 504.69 + } + }, + { + "id": "t_movie_gen_74", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.82, + "time": 132.56, + "distance": 1679.26, + "gen_feat_1": 497.39, + "gen_feat_2": 0.485217, + "gen_feat_3": 513.12 + } + }, + { + "id": "t_movie_gen_75", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.18, + "time": 134.95, + "distance": 1745.08, + "gen_feat_1": 491.08, + "gen_feat_2": 0.495277, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_movie_gen_76", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.16, + "time": 138.62, + "distance": 1666.98, + "gen_feat_1": 501.07, + "gen_feat_2": 0.506814, + "gen_feat_3": 489.44 + } + }, + { + "id": "t_movie_gen_77", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.76, + "time": 130.95, + "distance": 1675.39, + "gen_feat_1": 513.23, + "gen_feat_2": 0.496512, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_movie_gen_78", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.99, + "time": 132.12, + "distance": 1674.54, + "gen_feat_1": 495.99, + "gen_feat_2": 0.496439, + "gen_feat_3": 506.49 + } + }, + { + "id": "t_movie_gen_79", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.84, + "time": 132.9, + "distance": 1698.58, + "gen_feat_1": 486.83, + "gen_feat_2": 0.487385, + "gen_feat_3": 489.3 + } + }, + { + "id": "t_movie_gen_80", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 135.25, + "distance": 1703.48, + "gen_feat_1": 497.71, + "gen_feat_2": 0.506091, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_movie_gen_81", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.08, + "time": 138.34, + "distance": 1706.78, + "gen_feat_1": 501.18, + "gen_feat_2": 0.503416, + "gen_feat_3": 493.11 + } + }, + { + "id": "t_movie_gen_82", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.95, + "time": 132.28, + "distance": 1658.35, + "gen_feat_1": 488.13, + "gen_feat_2": 0.514958, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_83", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 135.04, + "distance": 1663.79, + "gen_feat_1": 495.07, + "gen_feat_2": 0.489223, + "gen_feat_3": 514.52 + } + }, + { + "id": "t_movie_gen_84", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.76, + "time": 137.41, + "distance": 1703.65, + "gen_feat_1": 504.9, + "gen_feat_2": 0.503529, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_movie_gen_85", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.08, + "time": 135.55, + "distance": 1691.79, + "gen_feat_1": 503.38, + "gen_feat_2": 0.5004, + "gen_feat_3": 510.63 + } + }, + { + "id": "t_movie_gen_86", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.24, + "time": 133.11, + "distance": 1689.53, + "gen_feat_1": 509.79, + "gen_feat_2": 0.49881, + "gen_feat_3": 488.86 + } + }, + { + "id": "t_movie_gen_87", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.89, + "time": 137.15, + "distance": 1698.06, + "gen_feat_1": 503.82, + "gen_feat_2": 0.50464, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_88", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.13, + "time": 131.18, + "distance": 1660.59, + "gen_feat_1": 492.85, + "gen_feat_2": 0.514114, + "gen_feat_3": 513.82 + } + }, + { + "id": "t_movie_gen_89", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.87, + "time": 135.02, + "distance": 1741.57, + "gen_feat_1": 501.92, + "gen_feat_2": 0.508398, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_90", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.28, + "time": 137.35, + "distance": 1718.09, + "gen_feat_1": 488.68, + "gen_feat_2": 0.49537, + "gen_feat_3": 493.95 + } + }, + { + "id": "t_movie_gen_91", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 137.3, + "distance": 1693.34, + "gen_feat_1": 493.19, + "gen_feat_2": 0.495672, + "gen_feat_3": 488.25 + } + }, + { + "id": "t_movie_gen_92", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.83, + "time": 137.58, + "distance": 1744.3, + "gen_feat_1": 491.56, + "gen_feat_2": 0.498387, + "gen_feat_3": 511.69 + } + }, + { + "id": "t_movie_gen_93", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.91, + "time": 133.34, + "distance": 1702.93, + "gen_feat_1": 488.01, + "gen_feat_2": 0.502779, + "gen_feat_3": 491.18 + } + }, + { + "id": "t_movie_gen_94", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 134.1, + "distance": 1680.7, + "gen_feat_1": 497.7, + "gen_feat_2": 0.497436, + "gen_feat_3": 502.47 + } + }, + { + "id": "t_movie_gen_95", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 136.67, + "distance": 1705.0, + "gen_feat_1": 488.28, + "gen_feat_2": 0.487878, + "gen_feat_3": 495.8 + } + }, + { + "id": "t_movie_gen_96", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.9, + "time": 134.07, + "distance": 1659.49, + "gen_feat_1": 492.47, + "gen_feat_2": 0.492451, + "gen_feat_3": 511.78 + } + }, + { + "id": "t_movie_gen_97", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.21, + "time": 134.31, + "distance": 1734.61, + "gen_feat_1": 493.2, + "gen_feat_2": 0.488477, + "gen_feat_3": 503.93 + } + }, + { + "id": "t_movie_gen_98", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 135.67, + "distance": 1729.26, + "gen_feat_1": 489.64, + "gen_feat_2": 0.491387, + "gen_feat_3": 506.86 + } + }, + { + "id": "t_movie_gen_99", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.79, + "time": 133.64, + "distance": 1673.71, + "gen_feat_1": 505.04, + "gen_feat_2": 0.505422, + "gen_feat_3": 513.37 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_dining", + "kind": "TASK", + "task_id": "t_dining" + }, + { + "id": "n_shopping", + "kind": "TASK", + "task_id": "t_shopping" + }, + { + "id": "n_movie", + "kind": "TASK", + "task_id": "t_movie" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "time": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "distance": { + "neutral": 0, + "compose": { + "seq": { + "fn": "MAX" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "c_within_2km", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "distance", + "op": "<=", + "value": 2000 + }, + { + "id": "c_time_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "time", + "op": "<=", + "value": 240, + "hard": false + }, + { + "id": "c_cost_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 100, + "hard": false + }, + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 50.07, + "hard": true + }, + { + "id": "gen_c_local_t_dining_time_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_dining" + ], + "attribute_id": "time", + "op": "<=", + "value": 59.79, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_dining", + "t_shopping" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_dining", + "t_movie" + ], + "hard": true + } + ], + "objective": { + "type": "MANY", + "targets": [ + "cost", + "distance", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "time" + ], + "weights": { + "cost": 0.17, + "distance": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "time": 0.16 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/zhang2014-entertainment-planner-running-example_many_soft.json b/experimentation/instances/zhang2014-entertainment-planner-running-example_many_soft.json new file mode 100644 index 0000000..80359f9 --- /dev/null +++ b/experimentation/instances/zhang2014-entertainment-planner-running-example_many_soft.json @@ -0,0 +1,4541 @@ +{ + "metadata": { + "id": "zhang2014-entertainment-planner-running-example_many_soft", + "name": "Personal Entertainment Planner (Zhang et al. 2014) [many, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:05Z", + "description": "Modeled from the motivating example in 'Context-aware Generic Service Discovery and Service Composition' (IEEE MobServ 2014).", + "paper": { + "title": "Context-aware Generic Service Discovery and Service Composition", + "authors": "Y. Zhang et al.", + "year": 2014, + "doi": "10.1109/MobServ.2014.27" + } + }, + "features": [ + { + "id": "cost", + "name": "Total money cost (USD)", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "time", + "name": "Total time cost (minutes)", + "direction": "MINIMIZE", + "unit": "min", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1440 + } + }, + { + "id": "distance", + "name": "Distance from user's current location (meters)", + "direction": "MINIMIZE", + "unit": "m", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 50000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_rest_autre_saison", + "name": "Restaurant L’Autre Saison" + }, + { + "id": "p_cinema_banque_scotia", + "name": "Cinema Banque Scotia Montreal" + }, + { + "id": "p_seven_night_club", + "name": "Seven Night Club" + }, + { + "id": "p_local_shopping", + "name": "Local Shopping (nearby venue)" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_dining", + "name": "Restaurant / Dining activity" + }, + { + "id": "t_shopping", + "name": "Shopping activity" + }, + { + "id": "t_movie", + "name": "Movie activity" + } + ], + "candidates": [ + { + "id": "c_dining_autre_saison", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison", + "features": { + "cost": 20, + "time": 60, + "distance": 1600, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_dining_seven_night_club", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Seven Night Club", + "features": { + "cost": 20, + "time": 60, + "distance": 1800, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopping_local", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue", + "features": { + "cost": 20, + "time": 45, + "distance": 1200, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_movie_the_help_banque_scotia", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal", + "features": { + "cost": 10, + "time": 135, + "distance": 1700, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_dining_gen_1", + "task_id": "t_dining", + "provider_id": "p_gen_shared", + "name": "Dinner at Restaurant L’Autre Saison (Gen Shared)", + "features": { + "cost": 20.2, + "time": 59.79, + "distance": 1570.05, + "gen_feat_1": 508.24, + "gen_feat_2": 0.514901, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_shopping_gen_1", + "task_id": "t_shopping", + "provider_id": "p_gen_shared", + "name": "Shopping at a nearby venue (Gen Shared)", + "features": { + "cost": 19.87, + "time": 44.98, + "distance": 1189.95, + "gen_feat_1": 485.24, + "gen_feat_2": 0.486287, + "gen_feat_3": 500.42 + } + }, + { + "id": "t_movie_gen_1", + "task_id": "t_movie", + "provider_id": "p_gen_shared", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen Shared)", + "features": { + "cost": 9.82, + "time": 134.28, + "distance": 1742.9, + "gen_feat_1": 512.03, + "gen_feat_2": 0.505972, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_dining_gen_2", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.53, + "time": 59.13, + "distance": 1559.02, + "gen_feat_1": 498.66, + "gen_feat_2": 0.488957, + "gen_feat_3": 503.61 + } + }, + { + "id": "t_dining_gen_3", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.94, + "time": 58.5, + "distance": 1591.09, + "gen_feat_1": 495.96, + "gen_feat_2": 0.504969, + "gen_feat_3": 506.77 + } + }, + { + "id": "t_dining_gen_4", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.8, + "time": 61.46, + "distance": 1629.91, + "gen_feat_1": 510.53, + "gen_feat_2": 0.508, + "gen_feat_3": 491.98 + } + }, + { + "id": "t_dining_gen_5", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.22, + "time": 60.39, + "distance": 1564.48, + "gen_feat_1": 491.41, + "gen_feat_2": 0.490673, + "gen_feat_3": 490.61 + } + }, + { + "id": "t_dining_gen_6", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.38, + "time": 58.67, + "distance": 1626.15, + "gen_feat_1": 488.5, + "gen_feat_2": 0.49348, + "gen_feat_3": 495.75 + } + }, + { + "id": "t_dining_gen_7", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.18, + "time": 60.72, + "distance": 1555.22, + "gen_feat_1": 505.8, + "gen_feat_2": 0.506719, + "gen_feat_3": 499.33 + } + }, + { + "id": "t_dining_gen_8", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.43, + "time": 59.64, + "distance": 1598.13, + "gen_feat_1": 503.89, + "gen_feat_2": 0.506945, + "gen_feat_3": 508.17 + } + }, + { + "id": "t_dining_gen_9", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.64, + "time": 60.54, + "distance": 1604.33, + "gen_feat_1": 486.84, + "gen_feat_2": 0.506628, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_dining_gen_10", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 60.17, + "distance": 1616.85, + "gen_feat_1": 507.44, + "gen_feat_2": 0.489997, + "gen_feat_3": 502.16 + } + }, + { + "id": "t_dining_gen_11", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.68, + "time": 59.16, + "distance": 1620.42, + "gen_feat_1": 507.98, + "gen_feat_2": 0.488942, + "gen_feat_3": 489.19 + } + }, + { + "id": "t_dining_gen_12", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.74, + "time": 59.04, + "distance": 1602.16, + "gen_feat_1": 504.58, + "gen_feat_2": 0.489389, + "gen_feat_3": 507.41 + } + }, + { + "id": "t_dining_gen_13", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.47, + "time": 58.89, + "distance": 1622.97, + "gen_feat_1": 492.31, + "gen_feat_2": 0.503154, + "gen_feat_3": 508.55 + } + }, + { + "id": "t_dining_gen_14", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.72, + "time": 58.91, + "distance": 1626.35, + "gen_feat_1": 509.41, + "gen_feat_2": 0.490291, + "gen_feat_3": 514.74 + } + }, + { + "id": "t_dining_gen_15", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.59, + "time": 60.67, + "distance": 1631.73, + "gen_feat_1": 493.43, + "gen_feat_2": 0.498961, + "gen_feat_3": 492.15 + } + }, + { + "id": "t_dining_gen_16", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.21, + "time": 59.57, + "distance": 1621.68, + "gen_feat_1": 502.04, + "gen_feat_2": 0.491944, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_dining_gen_17", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.33, + "time": 59.99, + "distance": 1602.82, + "gen_feat_1": 513.49, + "gen_feat_2": 0.510425, + "gen_feat_3": 506.46 + } + }, + { + "id": "t_dining_gen_18", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.02, + "time": 60.13, + "distance": 1639.2, + "gen_feat_1": 498.4, + "gen_feat_2": 0.499582, + "gen_feat_3": 504.62 + } + }, + { + "id": "t_dining_gen_19", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.03, + "time": 60.73, + "distance": 1642.13, + "gen_feat_1": 507.63, + "gen_feat_2": 0.500514, + "gen_feat_3": 495.73 + } + }, + { + "id": "t_dining_gen_20", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.33, + "time": 59.96, + "distance": 1568.96, + "gen_feat_1": 488.36, + "gen_feat_2": 0.514752, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_dining_gen_21", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.8, + "time": 58.42, + "distance": 1555.46, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486429, + "gen_feat_3": 488.41 + } + }, + { + "id": "t_dining_gen_22", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.66, + "time": 61.62, + "distance": 1580.67, + "gen_feat_1": 491.06, + "gen_feat_2": 0.506184, + "gen_feat_3": 501.23 + } + }, + { + "id": "t_dining_gen_23", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.42, + "time": 61.78, + "distance": 1622.72, + "gen_feat_1": 490.83, + "gen_feat_2": 0.489949, + "gen_feat_3": 487.73 + } + }, + { + "id": "t_dining_gen_24", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.71, + "time": 59.51, + "distance": 1580.85, + "gen_feat_1": 501.15, + "gen_feat_2": 0.50297, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_25", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.42, + "time": 61.41, + "distance": 1578.66, + "gen_feat_1": 507.39, + "gen_feat_2": 0.499268, + "gen_feat_3": 490.28 + } + }, + { + "id": "t_dining_gen_26", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.55, + "time": 58.26, + "distance": 1560.85, + "gen_feat_1": 492.17, + "gen_feat_2": 0.492399, + "gen_feat_3": 511.94 + } + }, + { + "id": "t_dining_gen_27", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.48, + "time": 58.34, + "distance": 1631.2, + "gen_feat_1": 498.39, + "gen_feat_2": 0.490821, + "gen_feat_3": 491.03 + } + }, + { + "id": "t_dining_gen_28", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.04, + "time": 61.28, + "distance": 1606.8, + "gen_feat_1": 512.73, + "gen_feat_2": 0.509267, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_dining_gen_29", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.76, + "time": 60.3, + "distance": 1569.61, + "gen_feat_1": 490.22, + "gen_feat_2": 0.496831, + "gen_feat_3": 496.53 + } + }, + { + "id": "t_dining_gen_30", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.71, + "time": 60.3, + "distance": 1623.3, + "gen_feat_1": 500.21, + "gen_feat_2": 0.496569, + "gen_feat_3": 498.99 + } + }, + { + "id": "t_dining_gen_31", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.86, + "time": 59.05, + "distance": 1588.58, + "gen_feat_1": 485.96, + "gen_feat_2": 0.512749, + "gen_feat_3": 498.55 + } + }, + { + "id": "t_dining_gen_32", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.8, + "time": 59.8, + "distance": 1560.3, + "gen_feat_1": 512.24, + "gen_feat_2": 0.486102, + "gen_feat_3": 508.8 + } + }, + { + "id": "t_dining_gen_33", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.49, + "time": 61.12, + "distance": 1612.82, + "gen_feat_1": 506.05, + "gen_feat_2": 0.504153, + "gen_feat_3": 510.28 + } + }, + { + "id": "t_dining_gen_34", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.66, + "time": 58.74, + "distance": 1627.51, + "gen_feat_1": 494.47, + "gen_feat_2": 0.509322, + "gen_feat_3": 485.53 + } + }, + { + "id": "t_dining_gen_35", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.14, + "time": 60.57, + "distance": 1626.08, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513739, + "gen_feat_3": 510.69 + } + }, + { + "id": "t_dining_gen_36", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.57, + "time": 58.38, + "distance": 1610.88, + "gen_feat_1": 495.23, + "gen_feat_2": 0.509726, + "gen_feat_3": 512.08 + } + }, + { + "id": "t_dining_gen_37", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.41, + "distance": 1575.46, + "gen_feat_1": 512.15, + "gen_feat_2": 0.492042, + "gen_feat_3": 505.13 + } + }, + { + "id": "t_dining_gen_38", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.22, + "time": 59.29, + "distance": 1557.64, + "gen_feat_1": 489.83, + "gen_feat_2": 0.49146, + "gen_feat_3": 495.3 + } + }, + { + "id": "t_dining_gen_39", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.59, + "time": 61.53, + "distance": 1562.65, + "gen_feat_1": 495.8, + "gen_feat_2": 0.496923, + "gen_feat_3": 507.91 + } + }, + { + "id": "t_dining_gen_40", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.43, + "time": 60.01, + "distance": 1604.0, + "gen_feat_1": 500.49, + "gen_feat_2": 0.514685, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_41", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.58, + "time": 60.72, + "distance": 1645.52, + "gen_feat_1": 487.19, + "gen_feat_2": 0.508959, + "gen_feat_3": 497.39 + } + }, + { + "id": "t_dining_gen_42", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.2, + "time": 59.26, + "distance": 1581.92, + "gen_feat_1": 509.7, + "gen_feat_2": 0.513201, + "gen_feat_3": 491.13 + } + }, + { + "id": "t_dining_gen_43", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.45, + "time": 60.26, + "distance": 1568.18, + "gen_feat_1": 493.86, + "gen_feat_2": 0.514555, + "gen_feat_3": 489.48 + } + }, + { + "id": "t_dining_gen_44", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.58, + "time": 58.5, + "distance": 1617.8, + "gen_feat_1": 491.08, + "gen_feat_2": 0.513671, + "gen_feat_3": 486.88 + } + }, + { + "id": "t_dining_gen_45", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.68, + "time": 61.23, + "distance": 1579.97, + "gen_feat_1": 509.82, + "gen_feat_2": 0.504088, + "gen_feat_3": 512.95 + } + }, + { + "id": "t_dining_gen_46", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 60.56, + "distance": 1641.45, + "gen_feat_1": 499.89, + "gen_feat_2": 0.510488, + "gen_feat_3": 491.3 + } + }, + { + "id": "t_dining_gen_47", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.94, + "time": 58.84, + "distance": 1629.37, + "gen_feat_1": 494.2, + "gen_feat_2": 0.49711, + "gen_feat_3": 496.8 + } + }, + { + "id": "t_dining_gen_48", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.23, + "time": 58.97, + "distance": 1607.14, + "gen_feat_1": 485.39, + "gen_feat_2": 0.485086, + "gen_feat_3": 504.57 + } + }, + { + "id": "t_dining_gen_49", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.47, + "time": 59.57, + "distance": 1615.57, + "gen_feat_1": 495.03, + "gen_feat_2": 0.503496, + "gen_feat_3": 509.51 + } + }, + { + "id": "t_dining_gen_50", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.7, + "distance": 1583.69, + "gen_feat_1": 489.31, + "gen_feat_2": 0.498993, + "gen_feat_3": 498.25 + } + }, + { + "id": "t_dining_gen_51", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.06, + "time": 60.11, + "distance": 1630.7, + "gen_feat_1": 507.83, + "gen_feat_2": 0.497927, + "gen_feat_3": 485.62 + } + }, + { + "id": "t_dining_gen_52", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.53, + "time": 58.59, + "distance": 1646.13, + "gen_feat_1": 489.54, + "gen_feat_2": 0.503777, + "gen_feat_3": 487.65 + } + }, + { + "id": "t_dining_gen_53", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.9, + "time": 58.5, + "distance": 1634.44, + "gen_feat_1": 514.43, + "gen_feat_2": 0.508093, + "gen_feat_3": 499.44 + } + }, + { + "id": "t_dining_gen_54", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.18, + "time": 58.68, + "distance": 1576.83, + "gen_feat_1": 491.93, + "gen_feat_2": 0.485409, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_dining_gen_55", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.0, + "distance": 1581.79, + "gen_feat_1": 489.92, + "gen_feat_2": 0.49016, + "gen_feat_3": 513.4 + } + }, + { + "id": "t_dining_gen_56", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.18, + "time": 61.73, + "distance": 1637.68, + "gen_feat_1": 492.48, + "gen_feat_2": 0.497966, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_dining_gen_57", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.2, + "time": 61.78, + "distance": 1646.08, + "gen_feat_1": 508.92, + "gen_feat_2": 0.500426, + "gen_feat_3": 499.7 + } + }, + { + "id": "t_dining_gen_58", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.57, + "time": 59.32, + "distance": 1580.58, + "gen_feat_1": 509.74, + "gen_feat_2": 0.510379, + "gen_feat_3": 512.86 + } + }, + { + "id": "t_dining_gen_59", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.54, + "time": 59.3, + "distance": 1570.05, + "gen_feat_1": 486.4, + "gen_feat_2": 0.503502, + "gen_feat_3": 498.65 + } + }, + { + "id": "t_dining_gen_60", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.18, + "time": 61.43, + "distance": 1636.11, + "gen_feat_1": 485.66, + "gen_feat_2": 0.498532, + "gen_feat_3": 506.32 + } + }, + { + "id": "t_dining_gen_61", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.01, + "time": 59.61, + "distance": 1626.73, + "gen_feat_1": 507.2, + "gen_feat_2": 0.505098, + "gen_feat_3": 499.85 + } + }, + { + "id": "t_dining_gen_62", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.22, + "time": 59.78, + "distance": 1646.36, + "gen_feat_1": 500.64, + "gen_feat_2": 0.500049, + "gen_feat_3": 504.88 + } + }, + { + "id": "t_dining_gen_63", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.11, + "time": 59.7, + "distance": 1621.52, + "gen_feat_1": 494.18, + "gen_feat_2": 0.498313, + "gen_feat_3": 506.17 + } + }, + { + "id": "t_dining_gen_64", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.71, + "time": 61.36, + "distance": 1568.12, + "gen_feat_1": 493.75, + "gen_feat_2": 0.505406, + "gen_feat_3": 512.82 + } + }, + { + "id": "t_dining_gen_65", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.4, + "time": 58.28, + "distance": 1604.89, + "gen_feat_1": 487.06, + "gen_feat_2": 0.502445, + "gen_feat_3": 511.12 + } + }, + { + "id": "t_dining_gen_66", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 59.57, + "distance": 1581.66, + "gen_feat_1": 513.25, + "gen_feat_2": 0.493068, + "gen_feat_3": 505.54 + } + }, + { + "id": "t_dining_gen_67", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.21, + "time": 60.81, + "distance": 1606.42, + "gen_feat_1": 493.36, + "gen_feat_2": 0.50459, + "gen_feat_3": 493.01 + } + }, + { + "id": "t_dining_gen_68", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 59.09, + "distance": 1611.43, + "gen_feat_1": 505.83, + "gen_feat_2": 0.502644, + "gen_feat_3": 504.4 + } + }, + { + "id": "t_dining_gen_69", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.92, + "time": 61.04, + "distance": 1579.9, + "gen_feat_1": 512.7, + "gen_feat_2": 0.488813, + "gen_feat_3": 500.85 + } + }, + { + "id": "t_dining_gen_70", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.74, + "time": 59.83, + "distance": 1615.86, + "gen_feat_1": 505.67, + "gen_feat_2": 0.48967, + "gen_feat_3": 503.59 + } + }, + { + "id": "t_dining_gen_71", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 61.74, + "distance": 1585.25, + "gen_feat_1": 495.74, + "gen_feat_2": 0.490106, + "gen_feat_3": 499.93 + } + }, + { + "id": "t_dining_gen_72", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.9, + "time": 58.61, + "distance": 1604.96, + "gen_feat_1": 509.49, + "gen_feat_2": 0.512456, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_73", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.41, + "time": 59.23, + "distance": 1631.69, + "gen_feat_1": 507.39, + "gen_feat_2": 0.504155, + "gen_feat_3": 514.37 + } + }, + { + "id": "t_dining_gen_74", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.5, + "time": 58.7, + "distance": 1628.56, + "gen_feat_1": 514.96, + "gen_feat_2": 0.498875, + "gen_feat_3": 512.16 + } + }, + { + "id": "t_dining_gen_75", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.83, + "time": 61.78, + "distance": 1589.19, + "gen_feat_1": 501.13, + "gen_feat_2": 0.504679, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_dining_gen_76", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.02, + "time": 61.78, + "distance": 1596.36, + "gen_feat_1": 511.57, + "gen_feat_2": 0.51185, + "gen_feat_3": 493.99 + } + }, + { + "id": "t_dining_gen_77", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.38, + "time": 59.52, + "distance": 1573.49, + "gen_feat_1": 513.61, + "gen_feat_2": 0.50886, + "gen_feat_3": 505.08 + } + }, + { + "id": "t_dining_gen_78", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.28, + "time": 59.03, + "distance": 1628.26, + "gen_feat_1": 513.77, + "gen_feat_2": 0.508209, + "gen_feat_3": 504.63 + } + }, + { + "id": "t_dining_gen_79", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.75, + "time": 60.98, + "distance": 1603.39, + "gen_feat_1": 510.74, + "gen_feat_2": 0.51442, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_dining_gen_80", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.34, + "time": 59.39, + "distance": 1607.15, + "gen_feat_1": 489.01, + "gen_feat_2": 0.508841, + "gen_feat_3": 503.65 + } + }, + { + "id": "t_dining_gen_81", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.78, + "time": 61.32, + "distance": 1606.79, + "gen_feat_1": 494.77, + "gen_feat_2": 0.498081, + "gen_feat_3": 490.68 + } + }, + { + "id": "t_dining_gen_82", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.0, + "time": 60.47, + "distance": 1578.03, + "gen_feat_1": 505.85, + "gen_feat_2": 0.496498, + "gen_feat_3": 494.3 + } + }, + { + "id": "t_dining_gen_83", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.59, + "time": 60.4, + "distance": 1576.41, + "gen_feat_1": 487.54, + "gen_feat_2": 0.490813, + "gen_feat_3": 506.97 + } + }, + { + "id": "t_dining_gen_84", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.45, + "time": 58.59, + "distance": 1635.41, + "gen_feat_1": 507.53, + "gen_feat_2": 0.499359, + "gen_feat_3": 511.49 + } + }, + { + "id": "t_dining_gen_85", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.55, + "time": 59.37, + "distance": 1578.95, + "gen_feat_1": 500.14, + "gen_feat_2": 0.504331, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_dining_gen_86", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.11, + "distance": 1556.1, + "gen_feat_1": 513.36, + "gen_feat_2": 0.512958, + "gen_feat_3": 493.44 + } + }, + { + "id": "t_dining_gen_87", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.26, + "time": 59.23, + "distance": 1563.62, + "gen_feat_1": 489.36, + "gen_feat_2": 0.51222, + "gen_feat_3": 503.86 + } + }, + { + "id": "t_dining_gen_88", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.46, + "time": 61.2, + "distance": 1588.14, + "gen_feat_1": 488.89, + "gen_feat_2": 0.496175, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_dining_gen_89", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.79, + "time": 58.63, + "distance": 1622.85, + "gen_feat_1": 512.62, + "gen_feat_2": 0.485995, + "gen_feat_3": 487.83 + } + }, + { + "id": "t_dining_gen_90", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.48, + "time": 58.69, + "distance": 1640.49, + "gen_feat_1": 511.37, + "gen_feat_2": 0.494218, + "gen_feat_3": 505.83 + } + }, + { + "id": "t_dining_gen_91", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.58, + "time": 58.72, + "distance": 1630.9, + "gen_feat_1": 505.33, + "gen_feat_2": 0.485446, + "gen_feat_3": 496.64 + } + }, + { + "id": "t_dining_gen_92", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.04, + "time": 59.56, + "distance": 1559.07, + "gen_feat_1": 491.21, + "gen_feat_2": 0.509726, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_93", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.84, + "time": 60.45, + "distance": 1596.68, + "gen_feat_1": 493.98, + "gen_feat_2": 0.489239, + "gen_feat_3": 493.56 + } + }, + { + "id": "t_dining_gen_94", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.56, + "time": 59.95, + "distance": 1630.28, + "gen_feat_1": 488.49, + "gen_feat_2": 0.505218, + "gen_feat_3": 491.42 + } + }, + { + "id": "t_dining_gen_95", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.97, + "time": 59.51, + "distance": 1593.3, + "gen_feat_1": 488.66, + "gen_feat_2": 0.490214, + "gen_feat_3": 504.25 + } + }, + { + "id": "t_dining_gen_96", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.85, + "time": 58.35, + "distance": 1552.26, + "gen_feat_1": 503.49, + "gen_feat_2": 0.48523, + "gen_feat_3": 504.39 + } + }, + { + "id": "t_dining_gen_97", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.51, + "time": 59.5, + "distance": 1634.44, + "gen_feat_1": 497.31, + "gen_feat_2": 0.5107, + "gen_feat_3": 507.86 + } + }, + { + "id": "t_dining_gen_98", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.5, + "time": 61.17, + "distance": 1593.89, + "gen_feat_1": 510.31, + "gen_feat_2": 0.50078, + "gen_feat_3": 494.95 + } + }, + { + "id": "t_shopping_gen_2", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.95, + "time": 44.3, + "distance": 1198.71, + "gen_feat_1": 508.4, + "gen_feat_2": 0.485625, + "gen_feat_3": 507.99 + } + }, + { + "id": "t_shopping_gen_3", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 44.18, + "distance": 1196.21, + "gen_feat_1": 485.72, + "gen_feat_2": 0.488455, + "gen_feat_3": 489.7 + } + }, + { + "id": "t_shopping_gen_4", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.78, + "time": 44.9, + "distance": 1179.12, + "gen_feat_1": 503.26, + "gen_feat_2": 0.498291, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_shopping_gen_5", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.51, + "time": 44.53, + "distance": 1216.23, + "gen_feat_1": 510.8, + "gen_feat_2": 0.507066, + "gen_feat_3": 504.03 + } + }, + { + "id": "t_shopping_gen_6", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.18, + "time": 44.06, + "distance": 1199.34, + "gen_feat_1": 501.17, + "gen_feat_2": 0.493458, + "gen_feat_3": 510.83 + } + }, + { + "id": "t_shopping_gen_7", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.59, + "time": 45.0, + "distance": 1183.14, + "gen_feat_1": 501.56, + "gen_feat_2": 0.496232, + "gen_feat_3": 496.33 + } + }, + { + "id": "t_shopping_gen_8", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.45, + "time": 43.75, + "distance": 1196.19, + "gen_feat_1": 488.54, + "gen_feat_2": 0.508864, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_9", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.29, + "time": 45.49, + "distance": 1235.6, + "gen_feat_1": 505.19, + "gen_feat_2": 0.486447, + "gen_feat_3": 505.3 + } + }, + { + "id": "t_shopping_gen_10", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.2, + "time": 44.86, + "distance": 1227.31, + "gen_feat_1": 487.19, + "gen_feat_2": 0.512416, + "gen_feat_3": 499.73 + } + }, + { + "id": "t_shopping_gen_11", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.86, + "time": 44.51, + "distance": 1227.77, + "gen_feat_1": 488.24, + "gen_feat_2": 0.510589, + "gen_feat_3": 510.74 + } + }, + { + "id": "t_shopping_gen_12", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.87, + "time": 44.69, + "distance": 1170.61, + "gen_feat_1": 503.79, + "gen_feat_2": 0.487994, + "gen_feat_3": 485.28 + } + }, + { + "id": "t_shopping_gen_13", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.87, + "time": 46.21, + "distance": 1228.85, + "gen_feat_1": 488.6, + "gen_feat_2": 0.499239, + "gen_feat_3": 503.2 + } + }, + { + "id": "t_shopping_gen_14", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.47, + "time": 44.09, + "distance": 1191.47, + "gen_feat_1": 510.69, + "gen_feat_2": 0.500607, + "gen_feat_3": 501.94 + } + }, + { + "id": "t_shopping_gen_15", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.91, + "time": 44.79, + "distance": 1194.44, + "gen_feat_1": 493.04, + "gen_feat_2": 0.493381, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_16", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.74, + "time": 45.76, + "distance": 1214.32, + "gen_feat_1": 508.04, + "gen_feat_2": 0.505849, + "gen_feat_3": 514.42 + } + }, + { + "id": "t_shopping_gen_17", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.56, + "time": 44.53, + "distance": 1186.46, + "gen_feat_1": 497.1, + "gen_feat_2": 0.507483, + "gen_feat_3": 487.33 + } + }, + { + "id": "t_shopping_gen_18", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.3, + "time": 46.02, + "distance": 1191.93, + "gen_feat_1": 502.5, + "gen_feat_2": 0.489832, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_shopping_gen_19", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.29, + "time": 44.76, + "distance": 1178.65, + "gen_feat_1": 486.31, + "gen_feat_2": 0.501927, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_shopping_gen_20", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.59, + "time": 45.62, + "distance": 1234.59, + "gen_feat_1": 508.23, + "gen_feat_2": 0.488622, + "gen_feat_3": 505.15 + } + }, + { + "id": "t_shopping_gen_21", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.41, + "time": 44.06, + "distance": 1185.1, + "gen_feat_1": 498.37, + "gen_feat_2": 0.491076, + "gen_feat_3": 502.07 + } + }, + { + "id": "t_shopping_gen_22", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.07, + "time": 45.23, + "distance": 1172.35, + "gen_feat_1": 489.15, + "gen_feat_2": 0.487341, + "gen_feat_3": 502.22 + } + }, + { + "id": "t_shopping_gen_23", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.07, + "time": 44.11, + "distance": 1228.63, + "gen_feat_1": 489.68, + "gen_feat_2": 0.497214, + "gen_feat_3": 510.3 + } + }, + { + "id": "t_shopping_gen_24", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.79, + "time": 45.29, + "distance": 1211.47, + "gen_feat_1": 513.99, + "gen_feat_2": 0.511272, + "gen_feat_3": 512.18 + } + }, + { + "id": "t_shopping_gen_25", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.49, + "time": 45.68, + "distance": 1197.16, + "gen_feat_1": 504.19, + "gen_feat_2": 0.507954, + "gen_feat_3": 509.7 + } + }, + { + "id": "t_shopping_gen_26", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.61, + "time": 45.73, + "distance": 1191.91, + "gen_feat_1": 499.13, + "gen_feat_2": 0.502797, + "gen_feat_3": 486.18 + } + }, + { + "id": "t_shopping_gen_27", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.64, + "time": 45.28, + "distance": 1176.71, + "gen_feat_1": 505.64, + "gen_feat_2": 0.491227, + "gen_feat_3": 508.35 + } + }, + { + "id": "t_shopping_gen_28", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.87, + "time": 45.0, + "distance": 1216.17, + "gen_feat_1": 500.61, + "gen_feat_2": 0.512609, + "gen_feat_3": 509.87 + } + }, + { + "id": "t_shopping_gen_29", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.37, + "time": 44.26, + "distance": 1180.24, + "gen_feat_1": 487.72, + "gen_feat_2": 0.485295, + "gen_feat_3": 487.2 + } + }, + { + "id": "t_shopping_gen_30", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.65, + "time": 44.57, + "distance": 1197.12, + "gen_feat_1": 500.2, + "gen_feat_2": 0.506494, + "gen_feat_3": 511.02 + } + }, + { + "id": "t_shopping_gen_31", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.54, + "time": 43.79, + "distance": 1190.28, + "gen_feat_1": 501.09, + "gen_feat_2": 0.496883, + "gen_feat_3": 504.0 + } + }, + { + "id": "t_shopping_gen_32", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.4, + "time": 44.15, + "distance": 1210.36, + "gen_feat_1": 506.65, + "gen_feat_2": 0.494619, + "gen_feat_3": 489.54 + } + }, + { + "id": "t_shopping_gen_33", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.78, + "time": 44.05, + "distance": 1224.7, + "gen_feat_1": 505.11, + "gen_feat_2": 0.497586, + "gen_feat_3": 502.56 + } + }, + { + "id": "t_shopping_gen_34", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.93, + "time": 45.15, + "distance": 1219.85, + "gen_feat_1": 498.34, + "gen_feat_2": 0.488983, + "gen_feat_3": 494.13 + } + }, + { + "id": "t_shopping_gen_35", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.82, + "time": 44.55, + "distance": 1224.73, + "gen_feat_1": 511.51, + "gen_feat_2": 0.504196, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_shopping_gen_36", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.86, + "time": 45.5, + "distance": 1196.08, + "gen_feat_1": 495.33, + "gen_feat_2": 0.498326, + "gen_feat_3": 486.34 + } + }, + { + "id": "t_shopping_gen_37", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.59, + "time": 44.26, + "distance": 1203.59, + "gen_feat_1": 496.81, + "gen_feat_2": 0.510331, + "gen_feat_3": 506.27 + } + }, + { + "id": "t_shopping_gen_38", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.92, + "time": 45.08, + "distance": 1203.94, + "gen_feat_1": 500.75, + "gen_feat_2": 0.49117, + "gen_feat_3": 491.78 + } + }, + { + "id": "t_shopping_gen_39", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.31, + "time": 46.16, + "distance": 1182.79, + "gen_feat_1": 497.1, + "gen_feat_2": 0.497946, + "gen_feat_3": 512.02 + } + }, + { + "id": "t_shopping_gen_40", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.54, + "time": 44.22, + "distance": 1217.58, + "gen_feat_1": 514.19, + "gen_feat_2": 0.507653, + "gen_feat_3": 502.34 + } + }, + { + "id": "t_shopping_gen_41", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.64, + "time": 44.32, + "distance": 1196.64, + "gen_feat_1": 510.6, + "gen_feat_2": 0.510227, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_42", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.93, + "time": 46.08, + "distance": 1215.22, + "gen_feat_1": 509.33, + "gen_feat_2": 0.489128, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_43", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.94, + "time": 46.06, + "distance": 1197.83, + "gen_feat_1": 494.23, + "gen_feat_2": 0.491429, + "gen_feat_3": 512.77 + } + }, + { + "id": "t_shopping_gen_44", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.62, + "time": 44.6, + "distance": 1228.92, + "gen_feat_1": 503.07, + "gen_feat_2": 0.497061, + "gen_feat_3": 508.73 + } + }, + { + "id": "t_shopping_gen_45", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.54, + "time": 45.8, + "distance": 1230.3, + "gen_feat_1": 498.44, + "gen_feat_2": 0.491182, + "gen_feat_3": 510.12 + } + }, + { + "id": "t_shopping_gen_46", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 44.28, + "distance": 1216.64, + "gen_feat_1": 488.95, + "gen_feat_2": 0.485686, + "gen_feat_3": 513.45 + } + }, + { + "id": "t_shopping_gen_47", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.4, + "time": 44.8, + "distance": 1210.54, + "gen_feat_1": 488.83, + "gen_feat_2": 0.508023, + "gen_feat_3": 485.22 + } + }, + { + "id": "t_shopping_gen_48", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.69, + "time": 44.94, + "distance": 1204.74, + "gen_feat_1": 504.02, + "gen_feat_2": 0.485166, + "gen_feat_3": 509.28 + } + }, + { + "id": "t_shopping_gen_49", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.63, + "time": 45.76, + "distance": 1234.29, + "gen_feat_1": 496.66, + "gen_feat_2": 0.510271, + "gen_feat_3": 488.57 + } + }, + { + "id": "t_shopping_gen_50", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.54, + "time": 44.91, + "distance": 1215.96, + "gen_feat_1": 509.77, + "gen_feat_2": 0.485673, + "gen_feat_3": 502.33 + } + }, + { + "id": "t_shopping_gen_51", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.48, + "time": 46.17, + "distance": 1186.08, + "gen_feat_1": 512.11, + "gen_feat_2": 0.491803, + "gen_feat_3": 503.47 + } + }, + { + "id": "t_shopping_gen_52", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.89, + "time": 44.45, + "distance": 1194.92, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486916, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_shopping_gen_53", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.35, + "time": 44.61, + "distance": 1191.25, + "gen_feat_1": 503.61, + "gen_feat_2": 0.493221, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_shopping_gen_54", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.73, + "time": 45.54, + "distance": 1223.55, + "gen_feat_1": 494.27, + "gen_feat_2": 0.490001, + "gen_feat_3": 493.72 + } + }, + { + "id": "t_shopping_gen_55", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 44.24, + "distance": 1228.06, + "gen_feat_1": 497.25, + "gen_feat_2": 0.49955, + "gen_feat_3": 486.14 + } + }, + { + "id": "t_shopping_gen_56", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.69, + "time": 44.04, + "distance": 1224.5, + "gen_feat_1": 492.29, + "gen_feat_2": 0.500032, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_57", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.68, + "time": 46.32, + "distance": 1227.05, + "gen_feat_1": 510.63, + "gen_feat_2": 0.51217, + "gen_feat_3": 489.8 + } + }, + { + "id": "t_shopping_gen_58", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.13, + "time": 45.42, + "distance": 1231.38, + "gen_feat_1": 499.25, + "gen_feat_2": 0.502657, + "gen_feat_3": 488.16 + } + }, + { + "id": "t_shopping_gen_59", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 45.04, + "distance": 1206.58, + "gen_feat_1": 488.66, + "gen_feat_2": 0.500622, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_shopping_gen_60", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.33, + "time": 46.0, + "distance": 1170.11, + "gen_feat_1": 511.4, + "gen_feat_2": 0.49549, + "gen_feat_3": 503.71 + } + }, + { + "id": "t_shopping_gen_61", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.18, + "time": 46.1, + "distance": 1190.97, + "gen_feat_1": 498.6, + "gen_feat_2": 0.501812, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_62", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.24, + "time": 45.7, + "distance": 1164.26, + "gen_feat_1": 485.26, + "gen_feat_2": 0.49031, + "gen_feat_3": 487.45 + } + }, + { + "id": "t_shopping_gen_63", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.17, + "time": 45.97, + "distance": 1190.2, + "gen_feat_1": 511.28, + "gen_feat_2": 0.51432, + "gen_feat_3": 513.58 + } + }, + { + "id": "t_shopping_gen_64", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.73, + "time": 44.03, + "distance": 1178.97, + "gen_feat_1": 487.49, + "gen_feat_2": 0.508632, + "gen_feat_3": 500.21 + } + }, + { + "id": "t_shopping_gen_65", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.67, + "time": 43.83, + "distance": 1176.27, + "gen_feat_1": 512.03, + "gen_feat_2": 0.49815, + "gen_feat_3": 501.03 + } + }, + { + "id": "t_shopping_gen_66", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.26, + "time": 44.73, + "distance": 1220.07, + "gen_feat_1": 504.64, + "gen_feat_2": 0.502789, + "gen_feat_3": 505.95 + } + }, + { + "id": "t_shopping_gen_67", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.81, + "time": 44.73, + "distance": 1180.99, + "gen_feat_1": 491.13, + "gen_feat_2": 0.488945, + "gen_feat_3": 487.4 + } + }, + { + "id": "t_shopping_gen_68", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.86, + "time": 43.67, + "distance": 1232.56, + "gen_feat_1": 512.67, + "gen_feat_2": 0.491258, + "gen_feat_3": 495.53 + } + }, + { + "id": "t_shopping_gen_69", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.0, + "time": 45.32, + "distance": 1179.79, + "gen_feat_1": 504.7, + "gen_feat_2": 0.501825, + "gen_feat_3": 494.35 + } + }, + { + "id": "t_shopping_gen_70", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 45.99, + "distance": 1206.39, + "gen_feat_1": 497.84, + "gen_feat_2": 0.509326, + "gen_feat_3": 508.37 + } + }, + { + "id": "t_shopping_gen_71", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.89, + "time": 44.23, + "distance": 1211.83, + "gen_feat_1": 489.02, + "gen_feat_2": 0.504569, + "gen_feat_3": 486.74 + } + }, + { + "id": "t_shopping_gen_72", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.25, + "time": 43.89, + "distance": 1218.83, + "gen_feat_1": 514.57, + "gen_feat_2": 0.487312, + "gen_feat_3": 491.96 + } + }, + { + "id": "t_shopping_gen_73", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 45.64, + "distance": 1171.76, + "gen_feat_1": 499.58, + "gen_feat_2": 0.499353, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_shopping_gen_74", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.51, + "time": 45.18, + "distance": 1235.16, + "gen_feat_1": 491.35, + "gen_feat_2": 0.488032, + "gen_feat_3": 508.76 + } + }, + { + "id": "t_shopping_gen_75", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.45, + "time": 45.29, + "distance": 1185.87, + "gen_feat_1": 506.16, + "gen_feat_2": 0.494622, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_shopping_gen_76", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.11, + "time": 44.39, + "distance": 1222.53, + "gen_feat_1": 507.53, + "gen_feat_2": 0.505002, + "gen_feat_3": 503.01 + } + }, + { + "id": "t_shopping_gen_77", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.93, + "time": 46.13, + "distance": 1210.75, + "gen_feat_1": 506.27, + "gen_feat_2": 0.505682, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_shopping_gen_78", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.16, + "time": 46.07, + "distance": 1210.7, + "gen_feat_1": 508.56, + "gen_feat_2": 0.487189, + "gen_feat_3": 504.12 + } + }, + { + "id": "t_shopping_gen_79", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.03, + "time": 45.66, + "distance": 1190.96, + "gen_feat_1": 489.72, + "gen_feat_2": 0.488214, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_shopping_gen_80", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.77, + "time": 45.73, + "distance": 1226.46, + "gen_feat_1": 498.85, + "gen_feat_2": 0.50612, + "gen_feat_3": 508.83 + } + }, + { + "id": "t_shopping_gen_81", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.19, + "time": 44.4, + "distance": 1207.41, + "gen_feat_1": 512.69, + "gen_feat_2": 0.49773, + "gen_feat_3": 499.57 + } + }, + { + "id": "t_shopping_gen_82", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.91, + "time": 45.81, + "distance": 1232.14, + "gen_feat_1": 501.37, + "gen_feat_2": 0.501413, + "gen_feat_3": 509.02 + } + }, + { + "id": "t_shopping_gen_83", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.46, + "time": 45.7, + "distance": 1201.06, + "gen_feat_1": 507.37, + "gen_feat_2": 0.512514, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_84", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.46, + "time": 45.7, + "distance": 1176.63, + "gen_feat_1": 500.57, + "gen_feat_2": 0.512907, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_shopping_gen_85", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.3, + "time": 44.77, + "distance": 1227.54, + "gen_feat_1": 488.72, + "gen_feat_2": 0.491267, + "gen_feat_3": 504.72 + } + }, + { + "id": "t_shopping_gen_86", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.53, + "time": 44.82, + "distance": 1227.19, + "gen_feat_1": 495.19, + "gen_feat_2": 0.506807, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_shopping_gen_87", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.76, + "time": 45.19, + "distance": 1197.27, + "gen_feat_1": 492.23, + "gen_feat_2": 0.502276, + "gen_feat_3": 497.83 + } + }, + { + "id": "t_shopping_gen_88", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.51, + "time": 46.32, + "distance": 1202.27, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500008, + "gen_feat_3": 494.37 + } + }, + { + "id": "t_shopping_gen_89", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.31, + "time": 45.09, + "distance": 1196.05, + "gen_feat_1": 488.52, + "gen_feat_2": 0.501783, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_90", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.15, + "time": 45.09, + "distance": 1187.36, + "gen_feat_1": 510.87, + "gen_feat_2": 0.48952, + "gen_feat_3": 487.44 + } + }, + { + "id": "t_shopping_gen_91", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.98, + "time": 44.28, + "distance": 1230.46, + "gen_feat_1": 494.85, + "gen_feat_2": 0.49072, + "gen_feat_3": 507.33 + } + }, + { + "id": "t_shopping_gen_92", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.46, + "time": 44.78, + "distance": 1190.65, + "gen_feat_1": 511.14, + "gen_feat_2": 0.491965, + "gen_feat_3": 510.07 + } + }, + { + "id": "t_shopping_gen_93", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 44.16, + "distance": 1232.76, + "gen_feat_1": 491.76, + "gen_feat_2": 0.49386, + "gen_feat_3": 489.99 + } + }, + { + "id": "t_shopping_gen_94", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.09, + "time": 45.07, + "distance": 1187.9, + "gen_feat_1": 500.36, + "gen_feat_2": 0.505173, + "gen_feat_3": 512.28 + } + }, + { + "id": "t_shopping_gen_95", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.29, + "time": 44.73, + "distance": 1224.17, + "gen_feat_1": 507.58, + "gen_feat_2": 0.48708, + "gen_feat_3": 511.59 + } + }, + { + "id": "t_shopping_gen_96", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.53, + "time": 43.89, + "distance": 1206.53, + "gen_feat_1": 493.71, + "gen_feat_2": 0.505153, + "gen_feat_3": 502.61 + } + }, + { + "id": "t_shopping_gen_97", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.6, + "time": 45.25, + "distance": 1198.77, + "gen_feat_1": 499.74, + "gen_feat_2": 0.499805, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_shopping_gen_98", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.94, + "time": 45.61, + "distance": 1168.51, + "gen_feat_1": 491.6, + "gen_feat_2": 0.511011, + "gen_feat_3": 491.45 + } + }, + { + "id": "t_shopping_gen_99", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.76, + "time": 45.99, + "distance": 1192.67, + "gen_feat_1": 500.07, + "gen_feat_2": 0.491787, + "gen_feat_3": 488.2 + } + }, + { + "id": "t_movie_gen_2", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.81, + "time": 138.02, + "distance": 1654.01, + "gen_feat_1": 503.91, + "gen_feat_2": 0.502664, + "gen_feat_3": 506.8 + } + }, + { + "id": "t_movie_gen_3", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.98, + "time": 133.32, + "distance": 1664.29, + "gen_feat_1": 491.47, + "gen_feat_2": 0.500325, + "gen_feat_3": 496.28 + } + }, + { + "id": "t_movie_gen_4", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.11, + "time": 136.06, + "distance": 1704.88, + "gen_feat_1": 505.19, + "gen_feat_2": 0.509953, + "gen_feat_3": 499.19 + } + }, + { + "id": "t_movie_gen_5", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.17, + "time": 136.4, + "distance": 1724.13, + "gen_feat_1": 511.77, + "gen_feat_2": 0.505076, + "gen_feat_3": 491.0 + } + }, + { + "id": "t_movie_gen_6", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.2, + "time": 137.15, + "distance": 1664.63, + "gen_feat_1": 514.48, + "gen_feat_2": 0.503771, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_movie_gen_7", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.16, + "time": 135.61, + "distance": 1726.58, + "gen_feat_1": 493.34, + "gen_feat_2": 0.493128, + "gen_feat_3": 491.4 + } + }, + { + "id": "t_movie_gen_8", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.91, + "time": 135.69, + "distance": 1678.5, + "gen_feat_1": 493.49, + "gen_feat_2": 0.506584, + "gen_feat_3": 491.95 + } + }, + { + "id": "t_movie_gen_9", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.09, + "time": 132.47, + "distance": 1682.74, + "gen_feat_1": 513.37, + "gen_feat_2": 0.496243, + "gen_feat_3": 510.52 + } + }, + { + "id": "t_movie_gen_10", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.25, + "time": 134.94, + "distance": 1683.72, + "gen_feat_1": 493.66, + "gen_feat_2": 0.502149, + "gen_feat_3": 491.38 + } + }, + { + "id": "t_movie_gen_11", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 132.2, + "distance": 1677.4, + "gen_feat_1": 513.51, + "gen_feat_2": 0.512663, + "gen_feat_3": 496.77 + } + }, + { + "id": "t_movie_gen_12", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.02, + "time": 136.12, + "distance": 1683.25, + "gen_feat_1": 486.72, + "gen_feat_2": 0.48763, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_movie_gen_13", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 131.91, + "distance": 1710.85, + "gen_feat_1": 493.33, + "gen_feat_2": 0.499006, + "gen_feat_3": 497.58 + } + }, + { + "id": "t_movie_gen_14", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.85, + "time": 137.69, + "distance": 1738.0, + "gen_feat_1": 501.65, + "gen_feat_2": 0.507629, + "gen_feat_3": 509.86 + } + }, + { + "id": "t_movie_gen_15", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.02, + "time": 133.61, + "distance": 1660.2, + "gen_feat_1": 512.64, + "gen_feat_2": 0.487548, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_movie_gen_16", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.2, + "time": 132.6, + "distance": 1669.36, + "gen_feat_1": 490.54, + "gen_feat_2": 0.507088, + "gen_feat_3": 496.37 + } + }, + { + "id": "t_movie_gen_17", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.25, + "time": 138.2, + "distance": 1711.42, + "gen_feat_1": 497.15, + "gen_feat_2": 0.513509, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_movie_gen_18", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.76, + "time": 136.31, + "distance": 1749.75, + "gen_feat_1": 514.83, + "gen_feat_2": 0.50335, + "gen_feat_3": 503.33 + } + }, + { + "id": "t_movie_gen_19", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 131.68, + "distance": 1656.52, + "gen_feat_1": 487.37, + "gen_feat_2": 0.493627, + "gen_feat_3": 508.19 + } + }, + { + "id": "t_movie_gen_20", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.9, + "time": 137.27, + "distance": 1709.53, + "gen_feat_1": 497.44, + "gen_feat_2": 0.486038, + "gen_feat_3": 502.32 + } + }, + { + "id": "t_movie_gen_21", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.83, + "time": 136.88, + "distance": 1708.94, + "gen_feat_1": 492.6, + "gen_feat_2": 0.496495, + "gen_feat_3": 490.83 + } + }, + { + "id": "t_movie_gen_22", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.12, + "time": 133.07, + "distance": 1711.62, + "gen_feat_1": 493.34, + "gen_feat_2": 0.499182, + "gen_feat_3": 499.28 + } + }, + { + "id": "t_movie_gen_23", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.12, + "time": 134.21, + "distance": 1736.25, + "gen_feat_1": 503.64, + "gen_feat_2": 0.5068, + "gen_feat_3": 489.21 + } + }, + { + "id": "t_movie_gen_24", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 132.64, + "distance": 1664.88, + "gen_feat_1": 510.09, + "gen_feat_2": 0.510289, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_movie_gen_25", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.1, + "time": 137.12, + "distance": 1701.34, + "gen_feat_1": 501.06, + "gen_feat_2": 0.49893, + "gen_feat_3": 507.73 + } + }, + { + "id": "t_movie_gen_26", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 136.45, + "distance": 1678.04, + "gen_feat_1": 494.8, + "gen_feat_2": 0.485118, + "gen_feat_3": 508.86 + } + }, + { + "id": "t_movie_gen_27", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.83, + "time": 134.67, + "distance": 1694.92, + "gen_feat_1": 503.64, + "gen_feat_2": 0.511029, + "gen_feat_3": 505.48 + } + }, + { + "id": "t_movie_gen_28", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.96, + "time": 138.62, + "distance": 1659.13, + "gen_feat_1": 491.47, + "gen_feat_2": 0.511429, + "gen_feat_3": 500.08 + } + }, + { + "id": "t_movie_gen_29", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.76, + "time": 138.64, + "distance": 1697.07, + "gen_feat_1": 498.44, + "gen_feat_2": 0.509025, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_movie_gen_30", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.39, + "distance": 1730.3, + "gen_feat_1": 510.02, + "gen_feat_2": 0.491101, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_31", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.28, + "time": 131.41, + "distance": 1685.65, + "gen_feat_1": 490.64, + "gen_feat_2": 0.485642, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_movie_gen_32", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.93, + "time": 134.98, + "distance": 1695.11, + "gen_feat_1": 501.21, + "gen_feat_2": 0.50543, + "gen_feat_3": 499.51 + } + }, + { + "id": "t_movie_gen_33", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.87, + "time": 137.83, + "distance": 1715.38, + "gen_feat_1": 513.71, + "gen_feat_2": 0.493568, + "gen_feat_3": 514.01 + } + }, + { + "id": "t_movie_gen_34", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.81, + "time": 132.4, + "distance": 1663.09, + "gen_feat_1": 506.91, + "gen_feat_2": 0.510638, + "gen_feat_3": 501.83 + } + }, + { + "id": "t_movie_gen_35", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.24, + "time": 136.79, + "distance": 1694.27, + "gen_feat_1": 510.84, + "gen_feat_2": 0.507452, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_movie_gen_36", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.16, + "time": 136.15, + "distance": 1670.24, + "gen_feat_1": 502.99, + "gen_feat_2": 0.495856, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_37", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.3, + "time": 136.48, + "distance": 1719.06, + "gen_feat_1": 512.77, + "gen_feat_2": 0.488773, + "gen_feat_3": 505.19 + } + }, + { + "id": "t_movie_gen_38", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.89, + "time": 137.8, + "distance": 1682.43, + "gen_feat_1": 514.67, + "gen_feat_2": 0.508214, + "gen_feat_3": 504.71 + } + }, + { + "id": "t_movie_gen_39", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.88, + "time": 136.94, + "distance": 1652.85, + "gen_feat_1": 499.19, + "gen_feat_2": 0.500729, + "gen_feat_3": 511.08 + } + }, + { + "id": "t_movie_gen_40", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.75, + "time": 136.81, + "distance": 1673.83, + "gen_feat_1": 510.5, + "gen_feat_2": 0.496266, + "gen_feat_3": 512.35 + } + }, + { + "id": "t_movie_gen_41", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.84, + "time": 133.13, + "distance": 1698.79, + "gen_feat_1": 504.79, + "gen_feat_2": 0.491761, + "gen_feat_3": 489.88 + } + }, + { + "id": "t_movie_gen_42", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.79, + "time": 132.71, + "distance": 1654.02, + "gen_feat_1": 488.54, + "gen_feat_2": 0.496646, + "gen_feat_3": 506.89 + } + }, + { + "id": "t_movie_gen_43", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.03, + "time": 135.73, + "distance": 1687.52, + "gen_feat_1": 489.12, + "gen_feat_2": 0.50799, + "gen_feat_3": 499.94 + } + }, + { + "id": "t_movie_gen_44", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.09, + "time": 138.68, + "distance": 1703.05, + "gen_feat_1": 510.12, + "gen_feat_2": 0.485551, + "gen_feat_3": 502.13 + } + }, + { + "id": "t_movie_gen_45", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.86, + "time": 133.42, + "distance": 1652.65, + "gen_feat_1": 488.6, + "gen_feat_2": 0.510397, + "gen_feat_3": 509.98 + } + }, + { + "id": "t_movie_gen_46", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.97, + "time": 131.94, + "distance": 1673.56, + "gen_feat_1": 486.56, + "gen_feat_2": 0.505523, + "gen_feat_3": 501.82 + } + }, + { + "id": "t_movie_gen_47", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.0, + "time": 133.55, + "distance": 1671.34, + "gen_feat_1": 488.32, + "gen_feat_2": 0.49915, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_movie_gen_48", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.06, + "time": 138.36, + "distance": 1677.66, + "gen_feat_1": 497.58, + "gen_feat_2": 0.497849, + "gen_feat_3": 488.29 + } + }, + { + "id": "t_movie_gen_49", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 133.95, + "distance": 1742.48, + "gen_feat_1": 495.5, + "gen_feat_2": 0.511503, + "gen_feat_3": 491.31 + } + }, + { + "id": "t_movie_gen_50", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.77, + "time": 135.54, + "distance": 1710.41, + "gen_feat_1": 487.97, + "gen_feat_2": 0.508317, + "gen_feat_3": 490.49 + } + }, + { + "id": "t_movie_gen_51", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.77, + "time": 135.9, + "distance": 1664.29, + "gen_feat_1": 513.14, + "gen_feat_2": 0.507714, + "gen_feat_3": 487.99 + } + }, + { + "id": "t_movie_gen_52", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.74, + "time": 133.36, + "distance": 1679.04, + "gen_feat_1": 502.14, + "gen_feat_2": 0.489374, + "gen_feat_3": 501.0 + } + }, + { + "id": "t_movie_gen_53", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.75, + "time": 137.75, + "distance": 1727.9, + "gen_feat_1": 494.43, + "gen_feat_2": 0.492795, + "gen_feat_3": 507.56 + } + }, + { + "id": "t_movie_gen_54", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 137.23, + "distance": 1749.88, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514964, + "gen_feat_3": 513.51 + } + }, + { + "id": "t_movie_gen_55", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.27, + "time": 131.7, + "distance": 1671.69, + "gen_feat_1": 491.71, + "gen_feat_2": 0.507637, + "gen_feat_3": 496.63 + } + }, + { + "id": "t_movie_gen_56", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.25, + "time": 133.82, + "distance": 1744.69, + "gen_feat_1": 513.96, + "gen_feat_2": 0.486719, + "gen_feat_3": 505.59 + } + }, + { + "id": "t_movie_gen_57", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.99, + "distance": 1687.02, + "gen_feat_1": 495.73, + "gen_feat_2": 0.497053, + "gen_feat_3": 485.08 + } + }, + { + "id": "t_movie_gen_58", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 134.0, + "distance": 1717.93, + "gen_feat_1": 498.58, + "gen_feat_2": 0.514512, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_movie_gen_59", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 135.99, + "distance": 1669.61, + "gen_feat_1": 506.91, + "gen_feat_2": 0.486343, + "gen_feat_3": 513.29 + } + }, + { + "id": "t_movie_gen_60", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 137.16, + "distance": 1727.65, + "gen_feat_1": 511.78, + "gen_feat_2": 0.498191, + "gen_feat_3": 495.09 + } + }, + { + "id": "t_movie_gen_61", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.06, + "time": 131.51, + "distance": 1688.72, + "gen_feat_1": 501.65, + "gen_feat_2": 0.503774, + "gen_feat_3": 494.98 + } + }, + { + "id": "t_movie_gen_62", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 134.94, + "distance": 1688.34, + "gen_feat_1": 486.17, + "gen_feat_2": 0.506252, + "gen_feat_3": 499.8 + } + }, + { + "id": "t_movie_gen_63", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.0, + "time": 132.52, + "distance": 1696.65, + "gen_feat_1": 514.69, + "gen_feat_2": 0.493209, + "gen_feat_3": 485.24 + } + }, + { + "id": "t_movie_gen_64", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.73, + "time": 131.33, + "distance": 1699.32, + "gen_feat_1": 494.73, + "gen_feat_2": 0.500638, + "gen_feat_3": 507.36 + } + }, + { + "id": "t_movie_gen_65", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.28, + "time": 135.57, + "distance": 1672.37, + "gen_feat_1": 512.61, + "gen_feat_2": 0.49003, + "gen_feat_3": 498.67 + } + }, + { + "id": "t_movie_gen_66", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.81, + "time": 133.8, + "distance": 1700.55, + "gen_feat_1": 512.0, + "gen_feat_2": 0.486179, + "gen_feat_3": 501.33 + } + }, + { + "id": "t_movie_gen_67", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.03, + "time": 131.77, + "distance": 1745.74, + "gen_feat_1": 503.3, + "gen_feat_2": 0.51441, + "gen_feat_3": 486.9 + } + }, + { + "id": "t_movie_gen_68", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.9, + "time": 137.31, + "distance": 1655.07, + "gen_feat_1": 485.6, + "gen_feat_2": 0.49856, + "gen_feat_3": 495.04 + } + }, + { + "id": "t_movie_gen_69", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.19, + "time": 137.9, + "distance": 1713.23, + "gen_feat_1": 510.23, + "gen_feat_2": 0.490473, + "gen_feat_3": 492.48 + } + }, + { + "id": "t_movie_gen_70", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.92, + "time": 137.74, + "distance": 1742.03, + "gen_feat_1": 497.94, + "gen_feat_2": 0.514756, + "gen_feat_3": 487.31 + } + }, + { + "id": "t_movie_gen_71", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.28, + "time": 134.06, + "distance": 1654.96, + "gen_feat_1": 510.56, + "gen_feat_2": 0.492021, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_movie_gen_72", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 135.82, + "distance": 1738.49, + "gen_feat_1": 500.42, + "gen_feat_2": 0.493135, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_73", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 134.69, + "distance": 1663.19, + "gen_feat_1": 491.2, + "gen_feat_2": 0.505794, + "gen_feat_3": 504.69 + } + }, + { + "id": "t_movie_gen_74", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.82, + "time": 132.56, + "distance": 1679.26, + "gen_feat_1": 497.39, + "gen_feat_2": 0.485217, + "gen_feat_3": 513.12 + } + }, + { + "id": "t_movie_gen_75", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.18, + "time": 134.95, + "distance": 1745.08, + "gen_feat_1": 491.08, + "gen_feat_2": 0.495277, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_movie_gen_76", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.16, + "time": 138.62, + "distance": 1666.98, + "gen_feat_1": 501.07, + "gen_feat_2": 0.506814, + "gen_feat_3": 489.44 + } + }, + { + "id": "t_movie_gen_77", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.76, + "time": 130.95, + "distance": 1675.39, + "gen_feat_1": 513.23, + "gen_feat_2": 0.496512, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_movie_gen_78", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.99, + "time": 132.12, + "distance": 1674.54, + "gen_feat_1": 495.99, + "gen_feat_2": 0.496439, + "gen_feat_3": 506.49 + } + }, + { + "id": "t_movie_gen_79", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.84, + "time": 132.9, + "distance": 1698.58, + "gen_feat_1": 486.83, + "gen_feat_2": 0.487385, + "gen_feat_3": 489.3 + } + }, + { + "id": "t_movie_gen_80", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 135.25, + "distance": 1703.48, + "gen_feat_1": 497.71, + "gen_feat_2": 0.506091, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_movie_gen_81", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.08, + "time": 138.34, + "distance": 1706.78, + "gen_feat_1": 501.18, + "gen_feat_2": 0.503416, + "gen_feat_3": 493.11 + } + }, + { + "id": "t_movie_gen_82", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.95, + "time": 132.28, + "distance": 1658.35, + "gen_feat_1": 488.13, + "gen_feat_2": 0.514958, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_83", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 135.04, + "distance": 1663.79, + "gen_feat_1": 495.07, + "gen_feat_2": 0.489223, + "gen_feat_3": 514.52 + } + }, + { + "id": "t_movie_gen_84", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.76, + "time": 137.41, + "distance": 1703.65, + "gen_feat_1": 504.9, + "gen_feat_2": 0.503529, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_movie_gen_85", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.08, + "time": 135.55, + "distance": 1691.79, + "gen_feat_1": 503.38, + "gen_feat_2": 0.5004, + "gen_feat_3": 510.63 + } + }, + { + "id": "t_movie_gen_86", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.24, + "time": 133.11, + "distance": 1689.53, + "gen_feat_1": 509.79, + "gen_feat_2": 0.49881, + "gen_feat_3": 488.86 + } + }, + { + "id": "t_movie_gen_87", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.89, + "time": 137.15, + "distance": 1698.06, + "gen_feat_1": 503.82, + "gen_feat_2": 0.50464, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_88", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.13, + "time": 131.18, + "distance": 1660.59, + "gen_feat_1": 492.85, + "gen_feat_2": 0.514114, + "gen_feat_3": 513.82 + } + }, + { + "id": "t_movie_gen_89", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.87, + "time": 135.02, + "distance": 1741.57, + "gen_feat_1": 501.92, + "gen_feat_2": 0.508398, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_90", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.28, + "time": 137.35, + "distance": 1718.09, + "gen_feat_1": 488.68, + "gen_feat_2": 0.49537, + "gen_feat_3": 493.95 + } + }, + { + "id": "t_movie_gen_91", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 137.3, + "distance": 1693.34, + "gen_feat_1": 493.19, + "gen_feat_2": 0.495672, + "gen_feat_3": 488.25 + } + }, + { + "id": "t_movie_gen_92", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.83, + "time": 137.58, + "distance": 1744.3, + "gen_feat_1": 491.56, + "gen_feat_2": 0.498387, + "gen_feat_3": 511.69 + } + }, + { + "id": "t_movie_gen_93", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.91, + "time": 133.34, + "distance": 1702.93, + "gen_feat_1": 488.01, + "gen_feat_2": 0.502779, + "gen_feat_3": 491.18 + } + }, + { + "id": "t_movie_gen_94", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 134.1, + "distance": 1680.7, + "gen_feat_1": 497.7, + "gen_feat_2": 0.497436, + "gen_feat_3": 502.47 + } + }, + { + "id": "t_movie_gen_95", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 136.67, + "distance": 1705.0, + "gen_feat_1": 488.28, + "gen_feat_2": 0.487878, + "gen_feat_3": 495.8 + } + }, + { + "id": "t_movie_gen_96", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.9, + "time": 134.07, + "distance": 1659.49, + "gen_feat_1": 492.47, + "gen_feat_2": 0.492451, + "gen_feat_3": 511.78 + } + }, + { + "id": "t_movie_gen_97", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.21, + "time": 134.31, + "distance": 1734.61, + "gen_feat_1": 493.2, + "gen_feat_2": 0.488477, + "gen_feat_3": 503.93 + } + }, + { + "id": "t_movie_gen_98", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 135.67, + "distance": 1729.26, + "gen_feat_1": 489.64, + "gen_feat_2": 0.491387, + "gen_feat_3": 506.86 + } + }, + { + "id": "t_movie_gen_99", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.79, + "time": 133.64, + "distance": 1673.71, + "gen_feat_1": 505.04, + "gen_feat_2": 0.505422, + "gen_feat_3": 513.37 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_dining", + "kind": "TASK", + "task_id": "t_dining" + }, + { + "id": "n_shopping", + "kind": "TASK", + "task_id": "t_shopping" + }, + { + "id": "n_movie", + "kind": "TASK", + "task_id": "t_movie" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "time": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "distance": { + "neutral": 0, + "compose": { + "seq": { + "fn": "MAX" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "c_within_2km", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "distance", + "op": "<=", + "value": 2000, + "hard": false + }, + { + "id": "c_time_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "time", + "op": "<=", + "value": 240, + "hard": false + }, + { + "id": "c_cost_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 100, + "hard": false + }, + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 50.07, + "hard": false + }, + { + "id": "gen_c_local_t_dining_time_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_dining" + ], + "attribute_id": "time", + "op": "<=", + "value": 59.79, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_dining", + "t_shopping" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_dining", + "t_movie" + ], + "hard": false + } + ], + "objective": { + "type": "MANY", + "targets": [ + "cost", + "distance", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "time" + ], + "weights": { + "cost": 0.17, + "distance": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "time": 0.16 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/zhang2014-entertainment-planner-running-example_mono_one_hard.json b/experimentation/instances/zhang2014-entertainment-planner-running-example_mono_one_hard.json new file mode 100644 index 0000000..8e86fbc --- /dev/null +++ b/experimentation/instances/zhang2014-entertainment-planner-running-example_mono_one_hard.json @@ -0,0 +1,4530 @@ +{ + "metadata": { + "id": "zhang2014-entertainment-planner-running-example_mono_one_hard", + "name": "Personal Entertainment Planner (Zhang et al. 2014) [mono_one, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:05Z", + "description": "Modeled from the motivating example in 'Context-aware Generic Service Discovery and Service Composition' (IEEE MobServ 2014).", + "paper": { + "title": "Context-aware Generic Service Discovery and Service Composition", + "authors": "Y. Zhang et al.", + "year": 2014, + "doi": "10.1109/MobServ.2014.27" + } + }, + "features": [ + { + "id": "cost", + "name": "Total money cost (USD)", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "time", + "name": "Total time cost (minutes)", + "direction": "MINIMIZE", + "unit": "min", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1440 + } + }, + { + "id": "distance", + "name": "Distance from user's current location (meters)", + "direction": "MINIMIZE", + "unit": "m", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 50000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_rest_autre_saison", + "name": "Restaurant L’Autre Saison" + }, + { + "id": "p_cinema_banque_scotia", + "name": "Cinema Banque Scotia Montreal" + }, + { + "id": "p_seven_night_club", + "name": "Seven Night Club" + }, + { + "id": "p_local_shopping", + "name": "Local Shopping (nearby venue)" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_dining", + "name": "Restaurant / Dining activity" + }, + { + "id": "t_shopping", + "name": "Shopping activity" + }, + { + "id": "t_movie", + "name": "Movie activity" + } + ], + "candidates": [ + { + "id": "c_dining_autre_saison", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison", + "features": { + "cost": 20, + "time": 60, + "distance": 1600, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_dining_seven_night_club", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Seven Night Club", + "features": { + "cost": 20, + "time": 60, + "distance": 1800, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopping_local", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue", + "features": { + "cost": 20, + "time": 45, + "distance": 1200, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_movie_the_help_banque_scotia", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal", + "features": { + "cost": 10, + "time": 135, + "distance": 1700, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_dining_gen_1", + "task_id": "t_dining", + "provider_id": "p_gen_shared", + "name": "Dinner at Restaurant L’Autre Saison (Gen Shared)", + "features": { + "cost": 20.2, + "time": 59.79, + "distance": 1570.05, + "gen_feat_1": 508.24, + "gen_feat_2": 0.514901, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_shopping_gen_1", + "task_id": "t_shopping", + "provider_id": "p_gen_shared", + "name": "Shopping at a nearby venue (Gen Shared)", + "features": { + "cost": 19.87, + "time": 44.98, + "distance": 1189.95, + "gen_feat_1": 485.24, + "gen_feat_2": 0.486287, + "gen_feat_3": 500.42 + } + }, + { + "id": "t_movie_gen_1", + "task_id": "t_movie", + "provider_id": "p_gen_shared", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen Shared)", + "features": { + "cost": 9.82, + "time": 134.28, + "distance": 1742.9, + "gen_feat_1": 512.03, + "gen_feat_2": 0.505972, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_dining_gen_2", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.53, + "time": 59.13, + "distance": 1559.02, + "gen_feat_1": 498.66, + "gen_feat_2": 0.488957, + "gen_feat_3": 503.61 + } + }, + { + "id": "t_dining_gen_3", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.94, + "time": 58.5, + "distance": 1591.09, + "gen_feat_1": 495.96, + "gen_feat_2": 0.504969, + "gen_feat_3": 506.77 + } + }, + { + "id": "t_dining_gen_4", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.8, + "time": 61.46, + "distance": 1629.91, + "gen_feat_1": 510.53, + "gen_feat_2": 0.508, + "gen_feat_3": 491.98 + } + }, + { + "id": "t_dining_gen_5", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.22, + "time": 60.39, + "distance": 1564.48, + "gen_feat_1": 491.41, + "gen_feat_2": 0.490673, + "gen_feat_3": 490.61 + } + }, + { + "id": "t_dining_gen_6", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.38, + "time": 58.67, + "distance": 1626.15, + "gen_feat_1": 488.5, + "gen_feat_2": 0.49348, + "gen_feat_3": 495.75 + } + }, + { + "id": "t_dining_gen_7", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.18, + "time": 60.72, + "distance": 1555.22, + "gen_feat_1": 505.8, + "gen_feat_2": 0.506719, + "gen_feat_3": 499.33 + } + }, + { + "id": "t_dining_gen_8", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.43, + "time": 59.64, + "distance": 1598.13, + "gen_feat_1": 503.89, + "gen_feat_2": 0.506945, + "gen_feat_3": 508.17 + } + }, + { + "id": "t_dining_gen_9", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.64, + "time": 60.54, + "distance": 1604.33, + "gen_feat_1": 486.84, + "gen_feat_2": 0.506628, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_dining_gen_10", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 60.17, + "distance": 1616.85, + "gen_feat_1": 507.44, + "gen_feat_2": 0.489997, + "gen_feat_3": 502.16 + } + }, + { + "id": "t_dining_gen_11", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.68, + "time": 59.16, + "distance": 1620.42, + "gen_feat_1": 507.98, + "gen_feat_2": 0.488942, + "gen_feat_3": 489.19 + } + }, + { + "id": "t_dining_gen_12", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.74, + "time": 59.04, + "distance": 1602.16, + "gen_feat_1": 504.58, + "gen_feat_2": 0.489389, + "gen_feat_3": 507.41 + } + }, + { + "id": "t_dining_gen_13", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.47, + "time": 58.89, + "distance": 1622.97, + "gen_feat_1": 492.31, + "gen_feat_2": 0.503154, + "gen_feat_3": 508.55 + } + }, + { + "id": "t_dining_gen_14", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.72, + "time": 58.91, + "distance": 1626.35, + "gen_feat_1": 509.41, + "gen_feat_2": 0.490291, + "gen_feat_3": 514.74 + } + }, + { + "id": "t_dining_gen_15", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.59, + "time": 60.67, + "distance": 1631.73, + "gen_feat_1": 493.43, + "gen_feat_2": 0.498961, + "gen_feat_3": 492.15 + } + }, + { + "id": "t_dining_gen_16", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.21, + "time": 59.57, + "distance": 1621.68, + "gen_feat_1": 502.04, + "gen_feat_2": 0.491944, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_dining_gen_17", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.33, + "time": 59.99, + "distance": 1602.82, + "gen_feat_1": 513.49, + "gen_feat_2": 0.510425, + "gen_feat_3": 506.46 + } + }, + { + "id": "t_dining_gen_18", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.02, + "time": 60.13, + "distance": 1639.2, + "gen_feat_1": 498.4, + "gen_feat_2": 0.499582, + "gen_feat_3": 504.62 + } + }, + { + "id": "t_dining_gen_19", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.03, + "time": 60.73, + "distance": 1642.13, + "gen_feat_1": 507.63, + "gen_feat_2": 0.500514, + "gen_feat_3": 495.73 + } + }, + { + "id": "t_dining_gen_20", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.33, + "time": 59.96, + "distance": 1568.96, + "gen_feat_1": 488.36, + "gen_feat_2": 0.514752, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_dining_gen_21", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.8, + "time": 58.42, + "distance": 1555.46, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486429, + "gen_feat_3": 488.41 + } + }, + { + "id": "t_dining_gen_22", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.66, + "time": 61.62, + "distance": 1580.67, + "gen_feat_1": 491.06, + "gen_feat_2": 0.506184, + "gen_feat_3": 501.23 + } + }, + { + "id": "t_dining_gen_23", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.42, + "time": 61.78, + "distance": 1622.72, + "gen_feat_1": 490.83, + "gen_feat_2": 0.489949, + "gen_feat_3": 487.73 + } + }, + { + "id": "t_dining_gen_24", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.71, + "time": 59.51, + "distance": 1580.85, + "gen_feat_1": 501.15, + "gen_feat_2": 0.50297, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_25", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.42, + "time": 61.41, + "distance": 1578.66, + "gen_feat_1": 507.39, + "gen_feat_2": 0.499268, + "gen_feat_3": 490.28 + } + }, + { + "id": "t_dining_gen_26", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.55, + "time": 58.26, + "distance": 1560.85, + "gen_feat_1": 492.17, + "gen_feat_2": 0.492399, + "gen_feat_3": 511.94 + } + }, + { + "id": "t_dining_gen_27", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.48, + "time": 58.34, + "distance": 1631.2, + "gen_feat_1": 498.39, + "gen_feat_2": 0.490821, + "gen_feat_3": 491.03 + } + }, + { + "id": "t_dining_gen_28", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.04, + "time": 61.28, + "distance": 1606.8, + "gen_feat_1": 512.73, + "gen_feat_2": 0.509267, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_dining_gen_29", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.76, + "time": 60.3, + "distance": 1569.61, + "gen_feat_1": 490.22, + "gen_feat_2": 0.496831, + "gen_feat_3": 496.53 + } + }, + { + "id": "t_dining_gen_30", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.71, + "time": 60.3, + "distance": 1623.3, + "gen_feat_1": 500.21, + "gen_feat_2": 0.496569, + "gen_feat_3": 498.99 + } + }, + { + "id": "t_dining_gen_31", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.86, + "time": 59.05, + "distance": 1588.58, + "gen_feat_1": 485.96, + "gen_feat_2": 0.512749, + "gen_feat_3": 498.55 + } + }, + { + "id": "t_dining_gen_32", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.8, + "time": 59.8, + "distance": 1560.3, + "gen_feat_1": 512.24, + "gen_feat_2": 0.486102, + "gen_feat_3": 508.8 + } + }, + { + "id": "t_dining_gen_33", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.49, + "time": 61.12, + "distance": 1612.82, + "gen_feat_1": 506.05, + "gen_feat_2": 0.504153, + "gen_feat_3": 510.28 + } + }, + { + "id": "t_dining_gen_34", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.66, + "time": 58.74, + "distance": 1627.51, + "gen_feat_1": 494.47, + "gen_feat_2": 0.509322, + "gen_feat_3": 485.53 + } + }, + { + "id": "t_dining_gen_35", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.14, + "time": 60.57, + "distance": 1626.08, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513739, + "gen_feat_3": 510.69 + } + }, + { + "id": "t_dining_gen_36", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.57, + "time": 58.38, + "distance": 1610.88, + "gen_feat_1": 495.23, + "gen_feat_2": 0.509726, + "gen_feat_3": 512.08 + } + }, + { + "id": "t_dining_gen_37", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.41, + "distance": 1575.46, + "gen_feat_1": 512.15, + "gen_feat_2": 0.492042, + "gen_feat_3": 505.13 + } + }, + { + "id": "t_dining_gen_38", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.22, + "time": 59.29, + "distance": 1557.64, + "gen_feat_1": 489.83, + "gen_feat_2": 0.49146, + "gen_feat_3": 495.3 + } + }, + { + "id": "t_dining_gen_39", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.59, + "time": 61.53, + "distance": 1562.65, + "gen_feat_1": 495.8, + "gen_feat_2": 0.496923, + "gen_feat_3": 507.91 + } + }, + { + "id": "t_dining_gen_40", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.43, + "time": 60.01, + "distance": 1604.0, + "gen_feat_1": 500.49, + "gen_feat_2": 0.514685, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_41", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.58, + "time": 60.72, + "distance": 1645.52, + "gen_feat_1": 487.19, + "gen_feat_2": 0.508959, + "gen_feat_3": 497.39 + } + }, + { + "id": "t_dining_gen_42", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.2, + "time": 59.26, + "distance": 1581.92, + "gen_feat_1": 509.7, + "gen_feat_2": 0.513201, + "gen_feat_3": 491.13 + } + }, + { + "id": "t_dining_gen_43", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.45, + "time": 60.26, + "distance": 1568.18, + "gen_feat_1": 493.86, + "gen_feat_2": 0.514555, + "gen_feat_3": 489.48 + } + }, + { + "id": "t_dining_gen_44", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.58, + "time": 58.5, + "distance": 1617.8, + "gen_feat_1": 491.08, + "gen_feat_2": 0.513671, + "gen_feat_3": 486.88 + } + }, + { + "id": "t_dining_gen_45", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.68, + "time": 61.23, + "distance": 1579.97, + "gen_feat_1": 509.82, + "gen_feat_2": 0.504088, + "gen_feat_3": 512.95 + } + }, + { + "id": "t_dining_gen_46", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 60.56, + "distance": 1641.45, + "gen_feat_1": 499.89, + "gen_feat_2": 0.510488, + "gen_feat_3": 491.3 + } + }, + { + "id": "t_dining_gen_47", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.94, + "time": 58.84, + "distance": 1629.37, + "gen_feat_1": 494.2, + "gen_feat_2": 0.49711, + "gen_feat_3": 496.8 + } + }, + { + "id": "t_dining_gen_48", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.23, + "time": 58.97, + "distance": 1607.14, + "gen_feat_1": 485.39, + "gen_feat_2": 0.485086, + "gen_feat_3": 504.57 + } + }, + { + "id": "t_dining_gen_49", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.47, + "time": 59.57, + "distance": 1615.57, + "gen_feat_1": 495.03, + "gen_feat_2": 0.503496, + "gen_feat_3": 509.51 + } + }, + { + "id": "t_dining_gen_50", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.7, + "distance": 1583.69, + "gen_feat_1": 489.31, + "gen_feat_2": 0.498993, + "gen_feat_3": 498.25 + } + }, + { + "id": "t_dining_gen_51", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.06, + "time": 60.11, + "distance": 1630.7, + "gen_feat_1": 507.83, + "gen_feat_2": 0.497927, + "gen_feat_3": 485.62 + } + }, + { + "id": "t_dining_gen_52", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.53, + "time": 58.59, + "distance": 1646.13, + "gen_feat_1": 489.54, + "gen_feat_2": 0.503777, + "gen_feat_3": 487.65 + } + }, + { + "id": "t_dining_gen_53", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.9, + "time": 58.5, + "distance": 1634.44, + "gen_feat_1": 514.43, + "gen_feat_2": 0.508093, + "gen_feat_3": 499.44 + } + }, + { + "id": "t_dining_gen_54", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.18, + "time": 58.68, + "distance": 1576.83, + "gen_feat_1": 491.93, + "gen_feat_2": 0.485409, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_dining_gen_55", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.0, + "distance": 1581.79, + "gen_feat_1": 489.92, + "gen_feat_2": 0.49016, + "gen_feat_3": 513.4 + } + }, + { + "id": "t_dining_gen_56", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.18, + "time": 61.73, + "distance": 1637.68, + "gen_feat_1": 492.48, + "gen_feat_2": 0.497966, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_dining_gen_57", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.2, + "time": 61.78, + "distance": 1646.08, + "gen_feat_1": 508.92, + "gen_feat_2": 0.500426, + "gen_feat_3": 499.7 + } + }, + { + "id": "t_dining_gen_58", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.57, + "time": 59.32, + "distance": 1580.58, + "gen_feat_1": 509.74, + "gen_feat_2": 0.510379, + "gen_feat_3": 512.86 + } + }, + { + "id": "t_dining_gen_59", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.54, + "time": 59.3, + "distance": 1570.05, + "gen_feat_1": 486.4, + "gen_feat_2": 0.503502, + "gen_feat_3": 498.65 + } + }, + { + "id": "t_dining_gen_60", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.18, + "time": 61.43, + "distance": 1636.11, + "gen_feat_1": 485.66, + "gen_feat_2": 0.498532, + "gen_feat_3": 506.32 + } + }, + { + "id": "t_dining_gen_61", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.01, + "time": 59.61, + "distance": 1626.73, + "gen_feat_1": 507.2, + "gen_feat_2": 0.505098, + "gen_feat_3": 499.85 + } + }, + { + "id": "t_dining_gen_62", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.22, + "time": 59.78, + "distance": 1646.36, + "gen_feat_1": 500.64, + "gen_feat_2": 0.500049, + "gen_feat_3": 504.88 + } + }, + { + "id": "t_dining_gen_63", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.11, + "time": 59.7, + "distance": 1621.52, + "gen_feat_1": 494.18, + "gen_feat_2": 0.498313, + "gen_feat_3": 506.17 + } + }, + { + "id": "t_dining_gen_64", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.71, + "time": 61.36, + "distance": 1568.12, + "gen_feat_1": 493.75, + "gen_feat_2": 0.505406, + "gen_feat_3": 512.82 + } + }, + { + "id": "t_dining_gen_65", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.4, + "time": 58.28, + "distance": 1604.89, + "gen_feat_1": 487.06, + "gen_feat_2": 0.502445, + "gen_feat_3": 511.12 + } + }, + { + "id": "t_dining_gen_66", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 59.57, + "distance": 1581.66, + "gen_feat_1": 513.25, + "gen_feat_2": 0.493068, + "gen_feat_3": 505.54 + } + }, + { + "id": "t_dining_gen_67", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.21, + "time": 60.81, + "distance": 1606.42, + "gen_feat_1": 493.36, + "gen_feat_2": 0.50459, + "gen_feat_3": 493.01 + } + }, + { + "id": "t_dining_gen_68", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 59.09, + "distance": 1611.43, + "gen_feat_1": 505.83, + "gen_feat_2": 0.502644, + "gen_feat_3": 504.4 + } + }, + { + "id": "t_dining_gen_69", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.92, + "time": 61.04, + "distance": 1579.9, + "gen_feat_1": 512.7, + "gen_feat_2": 0.488813, + "gen_feat_3": 500.85 + } + }, + { + "id": "t_dining_gen_70", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.74, + "time": 59.83, + "distance": 1615.86, + "gen_feat_1": 505.67, + "gen_feat_2": 0.48967, + "gen_feat_3": 503.59 + } + }, + { + "id": "t_dining_gen_71", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 61.74, + "distance": 1585.25, + "gen_feat_1": 495.74, + "gen_feat_2": 0.490106, + "gen_feat_3": 499.93 + } + }, + { + "id": "t_dining_gen_72", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.9, + "time": 58.61, + "distance": 1604.96, + "gen_feat_1": 509.49, + "gen_feat_2": 0.512456, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_73", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.41, + "time": 59.23, + "distance": 1631.69, + "gen_feat_1": 507.39, + "gen_feat_2": 0.504155, + "gen_feat_3": 514.37 + } + }, + { + "id": "t_dining_gen_74", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.5, + "time": 58.7, + "distance": 1628.56, + "gen_feat_1": 514.96, + "gen_feat_2": 0.498875, + "gen_feat_3": 512.16 + } + }, + { + "id": "t_dining_gen_75", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.83, + "time": 61.78, + "distance": 1589.19, + "gen_feat_1": 501.13, + "gen_feat_2": 0.504679, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_dining_gen_76", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.02, + "time": 61.78, + "distance": 1596.36, + "gen_feat_1": 511.57, + "gen_feat_2": 0.51185, + "gen_feat_3": 493.99 + } + }, + { + "id": "t_dining_gen_77", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.38, + "time": 59.52, + "distance": 1573.49, + "gen_feat_1": 513.61, + "gen_feat_2": 0.50886, + "gen_feat_3": 505.08 + } + }, + { + "id": "t_dining_gen_78", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.28, + "time": 59.03, + "distance": 1628.26, + "gen_feat_1": 513.77, + "gen_feat_2": 0.508209, + "gen_feat_3": 504.63 + } + }, + { + "id": "t_dining_gen_79", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.75, + "time": 60.98, + "distance": 1603.39, + "gen_feat_1": 510.74, + "gen_feat_2": 0.51442, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_dining_gen_80", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.34, + "time": 59.39, + "distance": 1607.15, + "gen_feat_1": 489.01, + "gen_feat_2": 0.508841, + "gen_feat_3": 503.65 + } + }, + { + "id": "t_dining_gen_81", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.78, + "time": 61.32, + "distance": 1606.79, + "gen_feat_1": 494.77, + "gen_feat_2": 0.498081, + "gen_feat_3": 490.68 + } + }, + { + "id": "t_dining_gen_82", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.0, + "time": 60.47, + "distance": 1578.03, + "gen_feat_1": 505.85, + "gen_feat_2": 0.496498, + "gen_feat_3": 494.3 + } + }, + { + "id": "t_dining_gen_83", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.59, + "time": 60.4, + "distance": 1576.41, + "gen_feat_1": 487.54, + "gen_feat_2": 0.490813, + "gen_feat_3": 506.97 + } + }, + { + "id": "t_dining_gen_84", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.45, + "time": 58.59, + "distance": 1635.41, + "gen_feat_1": 507.53, + "gen_feat_2": 0.499359, + "gen_feat_3": 511.49 + } + }, + { + "id": "t_dining_gen_85", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.55, + "time": 59.37, + "distance": 1578.95, + "gen_feat_1": 500.14, + "gen_feat_2": 0.504331, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_dining_gen_86", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.11, + "distance": 1556.1, + "gen_feat_1": 513.36, + "gen_feat_2": 0.512958, + "gen_feat_3": 493.44 + } + }, + { + "id": "t_dining_gen_87", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.26, + "time": 59.23, + "distance": 1563.62, + "gen_feat_1": 489.36, + "gen_feat_2": 0.51222, + "gen_feat_3": 503.86 + } + }, + { + "id": "t_dining_gen_88", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.46, + "time": 61.2, + "distance": 1588.14, + "gen_feat_1": 488.89, + "gen_feat_2": 0.496175, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_dining_gen_89", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.79, + "time": 58.63, + "distance": 1622.85, + "gen_feat_1": 512.62, + "gen_feat_2": 0.485995, + "gen_feat_3": 487.83 + } + }, + { + "id": "t_dining_gen_90", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.48, + "time": 58.69, + "distance": 1640.49, + "gen_feat_1": 511.37, + "gen_feat_2": 0.494218, + "gen_feat_3": 505.83 + } + }, + { + "id": "t_dining_gen_91", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.58, + "time": 58.72, + "distance": 1630.9, + "gen_feat_1": 505.33, + "gen_feat_2": 0.485446, + "gen_feat_3": 496.64 + } + }, + { + "id": "t_dining_gen_92", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.04, + "time": 59.56, + "distance": 1559.07, + "gen_feat_1": 491.21, + "gen_feat_2": 0.509726, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_93", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.84, + "time": 60.45, + "distance": 1596.68, + "gen_feat_1": 493.98, + "gen_feat_2": 0.489239, + "gen_feat_3": 493.56 + } + }, + { + "id": "t_dining_gen_94", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.56, + "time": 59.95, + "distance": 1630.28, + "gen_feat_1": 488.49, + "gen_feat_2": 0.505218, + "gen_feat_3": 491.42 + } + }, + { + "id": "t_dining_gen_95", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.97, + "time": 59.51, + "distance": 1593.3, + "gen_feat_1": 488.66, + "gen_feat_2": 0.490214, + "gen_feat_3": 504.25 + } + }, + { + "id": "t_dining_gen_96", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.85, + "time": 58.35, + "distance": 1552.26, + "gen_feat_1": 503.49, + "gen_feat_2": 0.48523, + "gen_feat_3": 504.39 + } + }, + { + "id": "t_dining_gen_97", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.51, + "time": 59.5, + "distance": 1634.44, + "gen_feat_1": 497.31, + "gen_feat_2": 0.5107, + "gen_feat_3": 507.86 + } + }, + { + "id": "t_dining_gen_98", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.5, + "time": 61.17, + "distance": 1593.89, + "gen_feat_1": 510.31, + "gen_feat_2": 0.50078, + "gen_feat_3": 494.95 + } + }, + { + "id": "t_shopping_gen_2", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.95, + "time": 44.3, + "distance": 1198.71, + "gen_feat_1": 508.4, + "gen_feat_2": 0.485625, + "gen_feat_3": 507.99 + } + }, + { + "id": "t_shopping_gen_3", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 44.18, + "distance": 1196.21, + "gen_feat_1": 485.72, + "gen_feat_2": 0.488455, + "gen_feat_3": 489.7 + } + }, + { + "id": "t_shopping_gen_4", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.78, + "time": 44.9, + "distance": 1179.12, + "gen_feat_1": 503.26, + "gen_feat_2": 0.498291, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_shopping_gen_5", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.51, + "time": 44.53, + "distance": 1216.23, + "gen_feat_1": 510.8, + "gen_feat_2": 0.507066, + "gen_feat_3": 504.03 + } + }, + { + "id": "t_shopping_gen_6", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.18, + "time": 44.06, + "distance": 1199.34, + "gen_feat_1": 501.17, + "gen_feat_2": 0.493458, + "gen_feat_3": 510.83 + } + }, + { + "id": "t_shopping_gen_7", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.59, + "time": 45.0, + "distance": 1183.14, + "gen_feat_1": 501.56, + "gen_feat_2": 0.496232, + "gen_feat_3": 496.33 + } + }, + { + "id": "t_shopping_gen_8", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.45, + "time": 43.75, + "distance": 1196.19, + "gen_feat_1": 488.54, + "gen_feat_2": 0.508864, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_9", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.29, + "time": 45.49, + "distance": 1235.6, + "gen_feat_1": 505.19, + "gen_feat_2": 0.486447, + "gen_feat_3": 505.3 + } + }, + { + "id": "t_shopping_gen_10", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.2, + "time": 44.86, + "distance": 1227.31, + "gen_feat_1": 487.19, + "gen_feat_2": 0.512416, + "gen_feat_3": 499.73 + } + }, + { + "id": "t_shopping_gen_11", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.86, + "time": 44.51, + "distance": 1227.77, + "gen_feat_1": 488.24, + "gen_feat_2": 0.510589, + "gen_feat_3": 510.74 + } + }, + { + "id": "t_shopping_gen_12", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.87, + "time": 44.69, + "distance": 1170.61, + "gen_feat_1": 503.79, + "gen_feat_2": 0.487994, + "gen_feat_3": 485.28 + } + }, + { + "id": "t_shopping_gen_13", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.87, + "time": 46.21, + "distance": 1228.85, + "gen_feat_1": 488.6, + "gen_feat_2": 0.499239, + "gen_feat_3": 503.2 + } + }, + { + "id": "t_shopping_gen_14", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.47, + "time": 44.09, + "distance": 1191.47, + "gen_feat_1": 510.69, + "gen_feat_2": 0.500607, + "gen_feat_3": 501.94 + } + }, + { + "id": "t_shopping_gen_15", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.91, + "time": 44.79, + "distance": 1194.44, + "gen_feat_1": 493.04, + "gen_feat_2": 0.493381, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_16", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.74, + "time": 45.76, + "distance": 1214.32, + "gen_feat_1": 508.04, + "gen_feat_2": 0.505849, + "gen_feat_3": 514.42 + } + }, + { + "id": "t_shopping_gen_17", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.56, + "time": 44.53, + "distance": 1186.46, + "gen_feat_1": 497.1, + "gen_feat_2": 0.507483, + "gen_feat_3": 487.33 + } + }, + { + "id": "t_shopping_gen_18", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.3, + "time": 46.02, + "distance": 1191.93, + "gen_feat_1": 502.5, + "gen_feat_2": 0.489832, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_shopping_gen_19", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.29, + "time": 44.76, + "distance": 1178.65, + "gen_feat_1": 486.31, + "gen_feat_2": 0.501927, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_shopping_gen_20", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.59, + "time": 45.62, + "distance": 1234.59, + "gen_feat_1": 508.23, + "gen_feat_2": 0.488622, + "gen_feat_3": 505.15 + } + }, + { + "id": "t_shopping_gen_21", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.41, + "time": 44.06, + "distance": 1185.1, + "gen_feat_1": 498.37, + "gen_feat_2": 0.491076, + "gen_feat_3": 502.07 + } + }, + { + "id": "t_shopping_gen_22", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.07, + "time": 45.23, + "distance": 1172.35, + "gen_feat_1": 489.15, + "gen_feat_2": 0.487341, + "gen_feat_3": 502.22 + } + }, + { + "id": "t_shopping_gen_23", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.07, + "time": 44.11, + "distance": 1228.63, + "gen_feat_1": 489.68, + "gen_feat_2": 0.497214, + "gen_feat_3": 510.3 + } + }, + { + "id": "t_shopping_gen_24", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.79, + "time": 45.29, + "distance": 1211.47, + "gen_feat_1": 513.99, + "gen_feat_2": 0.511272, + "gen_feat_3": 512.18 + } + }, + { + "id": "t_shopping_gen_25", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.49, + "time": 45.68, + "distance": 1197.16, + "gen_feat_1": 504.19, + "gen_feat_2": 0.507954, + "gen_feat_3": 509.7 + } + }, + { + "id": "t_shopping_gen_26", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.61, + "time": 45.73, + "distance": 1191.91, + "gen_feat_1": 499.13, + "gen_feat_2": 0.502797, + "gen_feat_3": 486.18 + } + }, + { + "id": "t_shopping_gen_27", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.64, + "time": 45.28, + "distance": 1176.71, + "gen_feat_1": 505.64, + "gen_feat_2": 0.491227, + "gen_feat_3": 508.35 + } + }, + { + "id": "t_shopping_gen_28", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.87, + "time": 45.0, + "distance": 1216.17, + "gen_feat_1": 500.61, + "gen_feat_2": 0.512609, + "gen_feat_3": 509.87 + } + }, + { + "id": "t_shopping_gen_29", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.37, + "time": 44.26, + "distance": 1180.24, + "gen_feat_1": 487.72, + "gen_feat_2": 0.485295, + "gen_feat_3": 487.2 + } + }, + { + "id": "t_shopping_gen_30", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.65, + "time": 44.57, + "distance": 1197.12, + "gen_feat_1": 500.2, + "gen_feat_2": 0.506494, + "gen_feat_3": 511.02 + } + }, + { + "id": "t_shopping_gen_31", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.54, + "time": 43.79, + "distance": 1190.28, + "gen_feat_1": 501.09, + "gen_feat_2": 0.496883, + "gen_feat_3": 504.0 + } + }, + { + "id": "t_shopping_gen_32", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.4, + "time": 44.15, + "distance": 1210.36, + "gen_feat_1": 506.65, + "gen_feat_2": 0.494619, + "gen_feat_3": 489.54 + } + }, + { + "id": "t_shopping_gen_33", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.78, + "time": 44.05, + "distance": 1224.7, + "gen_feat_1": 505.11, + "gen_feat_2": 0.497586, + "gen_feat_3": 502.56 + } + }, + { + "id": "t_shopping_gen_34", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.93, + "time": 45.15, + "distance": 1219.85, + "gen_feat_1": 498.34, + "gen_feat_2": 0.488983, + "gen_feat_3": 494.13 + } + }, + { + "id": "t_shopping_gen_35", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.82, + "time": 44.55, + "distance": 1224.73, + "gen_feat_1": 511.51, + "gen_feat_2": 0.504196, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_shopping_gen_36", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.86, + "time": 45.5, + "distance": 1196.08, + "gen_feat_1": 495.33, + "gen_feat_2": 0.498326, + "gen_feat_3": 486.34 + } + }, + { + "id": "t_shopping_gen_37", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.59, + "time": 44.26, + "distance": 1203.59, + "gen_feat_1": 496.81, + "gen_feat_2": 0.510331, + "gen_feat_3": 506.27 + } + }, + { + "id": "t_shopping_gen_38", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.92, + "time": 45.08, + "distance": 1203.94, + "gen_feat_1": 500.75, + "gen_feat_2": 0.49117, + "gen_feat_3": 491.78 + } + }, + { + "id": "t_shopping_gen_39", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.31, + "time": 46.16, + "distance": 1182.79, + "gen_feat_1": 497.1, + "gen_feat_2": 0.497946, + "gen_feat_3": 512.02 + } + }, + { + "id": "t_shopping_gen_40", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.54, + "time": 44.22, + "distance": 1217.58, + "gen_feat_1": 514.19, + "gen_feat_2": 0.507653, + "gen_feat_3": 502.34 + } + }, + { + "id": "t_shopping_gen_41", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.64, + "time": 44.32, + "distance": 1196.64, + "gen_feat_1": 510.6, + "gen_feat_2": 0.510227, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_42", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.93, + "time": 46.08, + "distance": 1215.22, + "gen_feat_1": 509.33, + "gen_feat_2": 0.489128, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_43", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.94, + "time": 46.06, + "distance": 1197.83, + "gen_feat_1": 494.23, + "gen_feat_2": 0.491429, + "gen_feat_3": 512.77 + } + }, + { + "id": "t_shopping_gen_44", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.62, + "time": 44.6, + "distance": 1228.92, + "gen_feat_1": 503.07, + "gen_feat_2": 0.497061, + "gen_feat_3": 508.73 + } + }, + { + "id": "t_shopping_gen_45", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.54, + "time": 45.8, + "distance": 1230.3, + "gen_feat_1": 498.44, + "gen_feat_2": 0.491182, + "gen_feat_3": 510.12 + } + }, + { + "id": "t_shopping_gen_46", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 44.28, + "distance": 1216.64, + "gen_feat_1": 488.95, + "gen_feat_2": 0.485686, + "gen_feat_3": 513.45 + } + }, + { + "id": "t_shopping_gen_47", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.4, + "time": 44.8, + "distance": 1210.54, + "gen_feat_1": 488.83, + "gen_feat_2": 0.508023, + "gen_feat_3": 485.22 + } + }, + { + "id": "t_shopping_gen_48", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.69, + "time": 44.94, + "distance": 1204.74, + "gen_feat_1": 504.02, + "gen_feat_2": 0.485166, + "gen_feat_3": 509.28 + } + }, + { + "id": "t_shopping_gen_49", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.63, + "time": 45.76, + "distance": 1234.29, + "gen_feat_1": 496.66, + "gen_feat_2": 0.510271, + "gen_feat_3": 488.57 + } + }, + { + "id": "t_shopping_gen_50", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.54, + "time": 44.91, + "distance": 1215.96, + "gen_feat_1": 509.77, + "gen_feat_2": 0.485673, + "gen_feat_3": 502.33 + } + }, + { + "id": "t_shopping_gen_51", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.48, + "time": 46.17, + "distance": 1186.08, + "gen_feat_1": 512.11, + "gen_feat_2": 0.491803, + "gen_feat_3": 503.47 + } + }, + { + "id": "t_shopping_gen_52", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.89, + "time": 44.45, + "distance": 1194.92, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486916, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_shopping_gen_53", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.35, + "time": 44.61, + "distance": 1191.25, + "gen_feat_1": 503.61, + "gen_feat_2": 0.493221, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_shopping_gen_54", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.73, + "time": 45.54, + "distance": 1223.55, + "gen_feat_1": 494.27, + "gen_feat_2": 0.490001, + "gen_feat_3": 493.72 + } + }, + { + "id": "t_shopping_gen_55", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 44.24, + "distance": 1228.06, + "gen_feat_1": 497.25, + "gen_feat_2": 0.49955, + "gen_feat_3": 486.14 + } + }, + { + "id": "t_shopping_gen_56", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.69, + "time": 44.04, + "distance": 1224.5, + "gen_feat_1": 492.29, + "gen_feat_2": 0.500032, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_57", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.68, + "time": 46.32, + "distance": 1227.05, + "gen_feat_1": 510.63, + "gen_feat_2": 0.51217, + "gen_feat_3": 489.8 + } + }, + { + "id": "t_shopping_gen_58", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.13, + "time": 45.42, + "distance": 1231.38, + "gen_feat_1": 499.25, + "gen_feat_2": 0.502657, + "gen_feat_3": 488.16 + } + }, + { + "id": "t_shopping_gen_59", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 45.04, + "distance": 1206.58, + "gen_feat_1": 488.66, + "gen_feat_2": 0.500622, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_shopping_gen_60", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.33, + "time": 46.0, + "distance": 1170.11, + "gen_feat_1": 511.4, + "gen_feat_2": 0.49549, + "gen_feat_3": 503.71 + } + }, + { + "id": "t_shopping_gen_61", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.18, + "time": 46.1, + "distance": 1190.97, + "gen_feat_1": 498.6, + "gen_feat_2": 0.501812, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_62", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.24, + "time": 45.7, + "distance": 1164.26, + "gen_feat_1": 485.26, + "gen_feat_2": 0.49031, + "gen_feat_3": 487.45 + } + }, + { + "id": "t_shopping_gen_63", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.17, + "time": 45.97, + "distance": 1190.2, + "gen_feat_1": 511.28, + "gen_feat_2": 0.51432, + "gen_feat_3": 513.58 + } + }, + { + "id": "t_shopping_gen_64", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.73, + "time": 44.03, + "distance": 1178.97, + "gen_feat_1": 487.49, + "gen_feat_2": 0.508632, + "gen_feat_3": 500.21 + } + }, + { + "id": "t_shopping_gen_65", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.67, + "time": 43.83, + "distance": 1176.27, + "gen_feat_1": 512.03, + "gen_feat_2": 0.49815, + "gen_feat_3": 501.03 + } + }, + { + "id": "t_shopping_gen_66", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.26, + "time": 44.73, + "distance": 1220.07, + "gen_feat_1": 504.64, + "gen_feat_2": 0.502789, + "gen_feat_3": 505.95 + } + }, + { + "id": "t_shopping_gen_67", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.81, + "time": 44.73, + "distance": 1180.99, + "gen_feat_1": 491.13, + "gen_feat_2": 0.488945, + "gen_feat_3": 487.4 + } + }, + { + "id": "t_shopping_gen_68", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.86, + "time": 43.67, + "distance": 1232.56, + "gen_feat_1": 512.67, + "gen_feat_2": 0.491258, + "gen_feat_3": 495.53 + } + }, + { + "id": "t_shopping_gen_69", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.0, + "time": 45.32, + "distance": 1179.79, + "gen_feat_1": 504.7, + "gen_feat_2": 0.501825, + "gen_feat_3": 494.35 + } + }, + { + "id": "t_shopping_gen_70", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 45.99, + "distance": 1206.39, + "gen_feat_1": 497.84, + "gen_feat_2": 0.509326, + "gen_feat_3": 508.37 + } + }, + { + "id": "t_shopping_gen_71", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.89, + "time": 44.23, + "distance": 1211.83, + "gen_feat_1": 489.02, + "gen_feat_2": 0.504569, + "gen_feat_3": 486.74 + } + }, + { + "id": "t_shopping_gen_72", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.25, + "time": 43.89, + "distance": 1218.83, + "gen_feat_1": 514.57, + "gen_feat_2": 0.487312, + "gen_feat_3": 491.96 + } + }, + { + "id": "t_shopping_gen_73", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 45.64, + "distance": 1171.76, + "gen_feat_1": 499.58, + "gen_feat_2": 0.499353, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_shopping_gen_74", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.51, + "time": 45.18, + "distance": 1235.16, + "gen_feat_1": 491.35, + "gen_feat_2": 0.488032, + "gen_feat_3": 508.76 + } + }, + { + "id": "t_shopping_gen_75", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.45, + "time": 45.29, + "distance": 1185.87, + "gen_feat_1": 506.16, + "gen_feat_2": 0.494622, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_shopping_gen_76", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.11, + "time": 44.39, + "distance": 1222.53, + "gen_feat_1": 507.53, + "gen_feat_2": 0.505002, + "gen_feat_3": 503.01 + } + }, + { + "id": "t_shopping_gen_77", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.93, + "time": 46.13, + "distance": 1210.75, + "gen_feat_1": 506.27, + "gen_feat_2": 0.505682, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_shopping_gen_78", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.16, + "time": 46.07, + "distance": 1210.7, + "gen_feat_1": 508.56, + "gen_feat_2": 0.487189, + "gen_feat_3": 504.12 + } + }, + { + "id": "t_shopping_gen_79", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.03, + "time": 45.66, + "distance": 1190.96, + "gen_feat_1": 489.72, + "gen_feat_2": 0.488214, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_shopping_gen_80", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.77, + "time": 45.73, + "distance": 1226.46, + "gen_feat_1": 498.85, + "gen_feat_2": 0.50612, + "gen_feat_3": 508.83 + } + }, + { + "id": "t_shopping_gen_81", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.19, + "time": 44.4, + "distance": 1207.41, + "gen_feat_1": 512.69, + "gen_feat_2": 0.49773, + "gen_feat_3": 499.57 + } + }, + { + "id": "t_shopping_gen_82", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.91, + "time": 45.81, + "distance": 1232.14, + "gen_feat_1": 501.37, + "gen_feat_2": 0.501413, + "gen_feat_3": 509.02 + } + }, + { + "id": "t_shopping_gen_83", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.46, + "time": 45.7, + "distance": 1201.06, + "gen_feat_1": 507.37, + "gen_feat_2": 0.512514, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_84", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.46, + "time": 45.7, + "distance": 1176.63, + "gen_feat_1": 500.57, + "gen_feat_2": 0.512907, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_shopping_gen_85", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.3, + "time": 44.77, + "distance": 1227.54, + "gen_feat_1": 488.72, + "gen_feat_2": 0.491267, + "gen_feat_3": 504.72 + } + }, + { + "id": "t_shopping_gen_86", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.53, + "time": 44.82, + "distance": 1227.19, + "gen_feat_1": 495.19, + "gen_feat_2": 0.506807, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_shopping_gen_87", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.76, + "time": 45.19, + "distance": 1197.27, + "gen_feat_1": 492.23, + "gen_feat_2": 0.502276, + "gen_feat_3": 497.83 + } + }, + { + "id": "t_shopping_gen_88", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.51, + "time": 46.32, + "distance": 1202.27, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500008, + "gen_feat_3": 494.37 + } + }, + { + "id": "t_shopping_gen_89", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.31, + "time": 45.09, + "distance": 1196.05, + "gen_feat_1": 488.52, + "gen_feat_2": 0.501783, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_90", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.15, + "time": 45.09, + "distance": 1187.36, + "gen_feat_1": 510.87, + "gen_feat_2": 0.48952, + "gen_feat_3": 487.44 + } + }, + { + "id": "t_shopping_gen_91", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.98, + "time": 44.28, + "distance": 1230.46, + "gen_feat_1": 494.85, + "gen_feat_2": 0.49072, + "gen_feat_3": 507.33 + } + }, + { + "id": "t_shopping_gen_92", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.46, + "time": 44.78, + "distance": 1190.65, + "gen_feat_1": 511.14, + "gen_feat_2": 0.491965, + "gen_feat_3": 510.07 + } + }, + { + "id": "t_shopping_gen_93", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 44.16, + "distance": 1232.76, + "gen_feat_1": 491.76, + "gen_feat_2": 0.49386, + "gen_feat_3": 489.99 + } + }, + { + "id": "t_shopping_gen_94", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.09, + "time": 45.07, + "distance": 1187.9, + "gen_feat_1": 500.36, + "gen_feat_2": 0.505173, + "gen_feat_3": 512.28 + } + }, + { + "id": "t_shopping_gen_95", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.29, + "time": 44.73, + "distance": 1224.17, + "gen_feat_1": 507.58, + "gen_feat_2": 0.48708, + "gen_feat_3": 511.59 + } + }, + { + "id": "t_shopping_gen_96", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.53, + "time": 43.89, + "distance": 1206.53, + "gen_feat_1": 493.71, + "gen_feat_2": 0.505153, + "gen_feat_3": 502.61 + } + }, + { + "id": "t_shopping_gen_97", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.6, + "time": 45.25, + "distance": 1198.77, + "gen_feat_1": 499.74, + "gen_feat_2": 0.499805, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_shopping_gen_98", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.94, + "time": 45.61, + "distance": 1168.51, + "gen_feat_1": 491.6, + "gen_feat_2": 0.511011, + "gen_feat_3": 491.45 + } + }, + { + "id": "t_shopping_gen_99", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.76, + "time": 45.99, + "distance": 1192.67, + "gen_feat_1": 500.07, + "gen_feat_2": 0.491787, + "gen_feat_3": 488.2 + } + }, + { + "id": "t_movie_gen_2", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.81, + "time": 138.02, + "distance": 1654.01, + "gen_feat_1": 503.91, + "gen_feat_2": 0.502664, + "gen_feat_3": 506.8 + } + }, + { + "id": "t_movie_gen_3", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.98, + "time": 133.32, + "distance": 1664.29, + "gen_feat_1": 491.47, + "gen_feat_2": 0.500325, + "gen_feat_3": 496.28 + } + }, + { + "id": "t_movie_gen_4", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.11, + "time": 136.06, + "distance": 1704.88, + "gen_feat_1": 505.19, + "gen_feat_2": 0.509953, + "gen_feat_3": 499.19 + } + }, + { + "id": "t_movie_gen_5", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.17, + "time": 136.4, + "distance": 1724.13, + "gen_feat_1": 511.77, + "gen_feat_2": 0.505076, + "gen_feat_3": 491.0 + } + }, + { + "id": "t_movie_gen_6", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.2, + "time": 137.15, + "distance": 1664.63, + "gen_feat_1": 514.48, + "gen_feat_2": 0.503771, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_movie_gen_7", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.16, + "time": 135.61, + "distance": 1726.58, + "gen_feat_1": 493.34, + "gen_feat_2": 0.493128, + "gen_feat_3": 491.4 + } + }, + { + "id": "t_movie_gen_8", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.91, + "time": 135.69, + "distance": 1678.5, + "gen_feat_1": 493.49, + "gen_feat_2": 0.506584, + "gen_feat_3": 491.95 + } + }, + { + "id": "t_movie_gen_9", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.09, + "time": 132.47, + "distance": 1682.74, + "gen_feat_1": 513.37, + "gen_feat_2": 0.496243, + "gen_feat_3": 510.52 + } + }, + { + "id": "t_movie_gen_10", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.25, + "time": 134.94, + "distance": 1683.72, + "gen_feat_1": 493.66, + "gen_feat_2": 0.502149, + "gen_feat_3": 491.38 + } + }, + { + "id": "t_movie_gen_11", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 132.2, + "distance": 1677.4, + "gen_feat_1": 513.51, + "gen_feat_2": 0.512663, + "gen_feat_3": 496.77 + } + }, + { + "id": "t_movie_gen_12", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.02, + "time": 136.12, + "distance": 1683.25, + "gen_feat_1": 486.72, + "gen_feat_2": 0.48763, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_movie_gen_13", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 131.91, + "distance": 1710.85, + "gen_feat_1": 493.33, + "gen_feat_2": 0.499006, + "gen_feat_3": 497.58 + } + }, + { + "id": "t_movie_gen_14", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.85, + "time": 137.69, + "distance": 1738.0, + "gen_feat_1": 501.65, + "gen_feat_2": 0.507629, + "gen_feat_3": 509.86 + } + }, + { + "id": "t_movie_gen_15", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.02, + "time": 133.61, + "distance": 1660.2, + "gen_feat_1": 512.64, + "gen_feat_2": 0.487548, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_movie_gen_16", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.2, + "time": 132.6, + "distance": 1669.36, + "gen_feat_1": 490.54, + "gen_feat_2": 0.507088, + "gen_feat_3": 496.37 + } + }, + { + "id": "t_movie_gen_17", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.25, + "time": 138.2, + "distance": 1711.42, + "gen_feat_1": 497.15, + "gen_feat_2": 0.513509, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_movie_gen_18", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.76, + "time": 136.31, + "distance": 1749.75, + "gen_feat_1": 514.83, + "gen_feat_2": 0.50335, + "gen_feat_3": 503.33 + } + }, + { + "id": "t_movie_gen_19", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 131.68, + "distance": 1656.52, + "gen_feat_1": 487.37, + "gen_feat_2": 0.493627, + "gen_feat_3": 508.19 + } + }, + { + "id": "t_movie_gen_20", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.9, + "time": 137.27, + "distance": 1709.53, + "gen_feat_1": 497.44, + "gen_feat_2": 0.486038, + "gen_feat_3": 502.32 + } + }, + { + "id": "t_movie_gen_21", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.83, + "time": 136.88, + "distance": 1708.94, + "gen_feat_1": 492.6, + "gen_feat_2": 0.496495, + "gen_feat_3": 490.83 + } + }, + { + "id": "t_movie_gen_22", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.12, + "time": 133.07, + "distance": 1711.62, + "gen_feat_1": 493.34, + "gen_feat_2": 0.499182, + "gen_feat_3": 499.28 + } + }, + { + "id": "t_movie_gen_23", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.12, + "time": 134.21, + "distance": 1736.25, + "gen_feat_1": 503.64, + "gen_feat_2": 0.5068, + "gen_feat_3": 489.21 + } + }, + { + "id": "t_movie_gen_24", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 132.64, + "distance": 1664.88, + "gen_feat_1": 510.09, + "gen_feat_2": 0.510289, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_movie_gen_25", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.1, + "time": 137.12, + "distance": 1701.34, + "gen_feat_1": 501.06, + "gen_feat_2": 0.49893, + "gen_feat_3": 507.73 + } + }, + { + "id": "t_movie_gen_26", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 136.45, + "distance": 1678.04, + "gen_feat_1": 494.8, + "gen_feat_2": 0.485118, + "gen_feat_3": 508.86 + } + }, + { + "id": "t_movie_gen_27", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.83, + "time": 134.67, + "distance": 1694.92, + "gen_feat_1": 503.64, + "gen_feat_2": 0.511029, + "gen_feat_3": 505.48 + } + }, + { + "id": "t_movie_gen_28", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.96, + "time": 138.62, + "distance": 1659.13, + "gen_feat_1": 491.47, + "gen_feat_2": 0.511429, + "gen_feat_3": 500.08 + } + }, + { + "id": "t_movie_gen_29", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.76, + "time": 138.64, + "distance": 1697.07, + "gen_feat_1": 498.44, + "gen_feat_2": 0.509025, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_movie_gen_30", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.39, + "distance": 1730.3, + "gen_feat_1": 510.02, + "gen_feat_2": 0.491101, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_31", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.28, + "time": 131.41, + "distance": 1685.65, + "gen_feat_1": 490.64, + "gen_feat_2": 0.485642, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_movie_gen_32", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.93, + "time": 134.98, + "distance": 1695.11, + "gen_feat_1": 501.21, + "gen_feat_2": 0.50543, + "gen_feat_3": 499.51 + } + }, + { + "id": "t_movie_gen_33", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.87, + "time": 137.83, + "distance": 1715.38, + "gen_feat_1": 513.71, + "gen_feat_2": 0.493568, + "gen_feat_3": 514.01 + } + }, + { + "id": "t_movie_gen_34", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.81, + "time": 132.4, + "distance": 1663.09, + "gen_feat_1": 506.91, + "gen_feat_2": 0.510638, + "gen_feat_3": 501.83 + } + }, + { + "id": "t_movie_gen_35", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.24, + "time": 136.79, + "distance": 1694.27, + "gen_feat_1": 510.84, + "gen_feat_2": 0.507452, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_movie_gen_36", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.16, + "time": 136.15, + "distance": 1670.24, + "gen_feat_1": 502.99, + "gen_feat_2": 0.495856, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_37", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.3, + "time": 136.48, + "distance": 1719.06, + "gen_feat_1": 512.77, + "gen_feat_2": 0.488773, + "gen_feat_3": 505.19 + } + }, + { + "id": "t_movie_gen_38", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.89, + "time": 137.8, + "distance": 1682.43, + "gen_feat_1": 514.67, + "gen_feat_2": 0.508214, + "gen_feat_3": 504.71 + } + }, + { + "id": "t_movie_gen_39", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.88, + "time": 136.94, + "distance": 1652.85, + "gen_feat_1": 499.19, + "gen_feat_2": 0.500729, + "gen_feat_3": 511.08 + } + }, + { + "id": "t_movie_gen_40", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.75, + "time": 136.81, + "distance": 1673.83, + "gen_feat_1": 510.5, + "gen_feat_2": 0.496266, + "gen_feat_3": 512.35 + } + }, + { + "id": "t_movie_gen_41", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.84, + "time": 133.13, + "distance": 1698.79, + "gen_feat_1": 504.79, + "gen_feat_2": 0.491761, + "gen_feat_3": 489.88 + } + }, + { + "id": "t_movie_gen_42", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.79, + "time": 132.71, + "distance": 1654.02, + "gen_feat_1": 488.54, + "gen_feat_2": 0.496646, + "gen_feat_3": 506.89 + } + }, + { + "id": "t_movie_gen_43", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.03, + "time": 135.73, + "distance": 1687.52, + "gen_feat_1": 489.12, + "gen_feat_2": 0.50799, + "gen_feat_3": 499.94 + } + }, + { + "id": "t_movie_gen_44", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.09, + "time": 138.68, + "distance": 1703.05, + "gen_feat_1": 510.12, + "gen_feat_2": 0.485551, + "gen_feat_3": 502.13 + } + }, + { + "id": "t_movie_gen_45", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.86, + "time": 133.42, + "distance": 1652.65, + "gen_feat_1": 488.6, + "gen_feat_2": 0.510397, + "gen_feat_3": 509.98 + } + }, + { + "id": "t_movie_gen_46", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.97, + "time": 131.94, + "distance": 1673.56, + "gen_feat_1": 486.56, + "gen_feat_2": 0.505523, + "gen_feat_3": 501.82 + } + }, + { + "id": "t_movie_gen_47", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.0, + "time": 133.55, + "distance": 1671.34, + "gen_feat_1": 488.32, + "gen_feat_2": 0.49915, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_movie_gen_48", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.06, + "time": 138.36, + "distance": 1677.66, + "gen_feat_1": 497.58, + "gen_feat_2": 0.497849, + "gen_feat_3": 488.29 + } + }, + { + "id": "t_movie_gen_49", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 133.95, + "distance": 1742.48, + "gen_feat_1": 495.5, + "gen_feat_2": 0.511503, + "gen_feat_3": 491.31 + } + }, + { + "id": "t_movie_gen_50", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.77, + "time": 135.54, + "distance": 1710.41, + "gen_feat_1": 487.97, + "gen_feat_2": 0.508317, + "gen_feat_3": 490.49 + } + }, + { + "id": "t_movie_gen_51", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.77, + "time": 135.9, + "distance": 1664.29, + "gen_feat_1": 513.14, + "gen_feat_2": 0.507714, + "gen_feat_3": 487.99 + } + }, + { + "id": "t_movie_gen_52", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.74, + "time": 133.36, + "distance": 1679.04, + "gen_feat_1": 502.14, + "gen_feat_2": 0.489374, + "gen_feat_3": 501.0 + } + }, + { + "id": "t_movie_gen_53", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.75, + "time": 137.75, + "distance": 1727.9, + "gen_feat_1": 494.43, + "gen_feat_2": 0.492795, + "gen_feat_3": 507.56 + } + }, + { + "id": "t_movie_gen_54", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 137.23, + "distance": 1749.88, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514964, + "gen_feat_3": 513.51 + } + }, + { + "id": "t_movie_gen_55", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.27, + "time": 131.7, + "distance": 1671.69, + "gen_feat_1": 491.71, + "gen_feat_2": 0.507637, + "gen_feat_3": 496.63 + } + }, + { + "id": "t_movie_gen_56", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.25, + "time": 133.82, + "distance": 1744.69, + "gen_feat_1": 513.96, + "gen_feat_2": 0.486719, + "gen_feat_3": 505.59 + } + }, + { + "id": "t_movie_gen_57", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.99, + "distance": 1687.02, + "gen_feat_1": 495.73, + "gen_feat_2": 0.497053, + "gen_feat_3": 485.08 + } + }, + { + "id": "t_movie_gen_58", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 134.0, + "distance": 1717.93, + "gen_feat_1": 498.58, + "gen_feat_2": 0.514512, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_movie_gen_59", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 135.99, + "distance": 1669.61, + "gen_feat_1": 506.91, + "gen_feat_2": 0.486343, + "gen_feat_3": 513.29 + } + }, + { + "id": "t_movie_gen_60", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 137.16, + "distance": 1727.65, + "gen_feat_1": 511.78, + "gen_feat_2": 0.498191, + "gen_feat_3": 495.09 + } + }, + { + "id": "t_movie_gen_61", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.06, + "time": 131.51, + "distance": 1688.72, + "gen_feat_1": 501.65, + "gen_feat_2": 0.503774, + "gen_feat_3": 494.98 + } + }, + { + "id": "t_movie_gen_62", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 134.94, + "distance": 1688.34, + "gen_feat_1": 486.17, + "gen_feat_2": 0.506252, + "gen_feat_3": 499.8 + } + }, + { + "id": "t_movie_gen_63", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.0, + "time": 132.52, + "distance": 1696.65, + "gen_feat_1": 514.69, + "gen_feat_2": 0.493209, + "gen_feat_3": 485.24 + } + }, + { + "id": "t_movie_gen_64", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.73, + "time": 131.33, + "distance": 1699.32, + "gen_feat_1": 494.73, + "gen_feat_2": 0.500638, + "gen_feat_3": 507.36 + } + }, + { + "id": "t_movie_gen_65", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.28, + "time": 135.57, + "distance": 1672.37, + "gen_feat_1": 512.61, + "gen_feat_2": 0.49003, + "gen_feat_3": 498.67 + } + }, + { + "id": "t_movie_gen_66", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.81, + "time": 133.8, + "distance": 1700.55, + "gen_feat_1": 512.0, + "gen_feat_2": 0.486179, + "gen_feat_3": 501.33 + } + }, + { + "id": "t_movie_gen_67", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.03, + "time": 131.77, + "distance": 1745.74, + "gen_feat_1": 503.3, + "gen_feat_2": 0.51441, + "gen_feat_3": 486.9 + } + }, + { + "id": "t_movie_gen_68", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.9, + "time": 137.31, + "distance": 1655.07, + "gen_feat_1": 485.6, + "gen_feat_2": 0.49856, + "gen_feat_3": 495.04 + } + }, + { + "id": "t_movie_gen_69", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.19, + "time": 137.9, + "distance": 1713.23, + "gen_feat_1": 510.23, + "gen_feat_2": 0.490473, + "gen_feat_3": 492.48 + } + }, + { + "id": "t_movie_gen_70", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.92, + "time": 137.74, + "distance": 1742.03, + "gen_feat_1": 497.94, + "gen_feat_2": 0.514756, + "gen_feat_3": 487.31 + } + }, + { + "id": "t_movie_gen_71", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.28, + "time": 134.06, + "distance": 1654.96, + "gen_feat_1": 510.56, + "gen_feat_2": 0.492021, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_movie_gen_72", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 135.82, + "distance": 1738.49, + "gen_feat_1": 500.42, + "gen_feat_2": 0.493135, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_73", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 134.69, + "distance": 1663.19, + "gen_feat_1": 491.2, + "gen_feat_2": 0.505794, + "gen_feat_3": 504.69 + } + }, + { + "id": "t_movie_gen_74", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.82, + "time": 132.56, + "distance": 1679.26, + "gen_feat_1": 497.39, + "gen_feat_2": 0.485217, + "gen_feat_3": 513.12 + } + }, + { + "id": "t_movie_gen_75", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.18, + "time": 134.95, + "distance": 1745.08, + "gen_feat_1": 491.08, + "gen_feat_2": 0.495277, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_movie_gen_76", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.16, + "time": 138.62, + "distance": 1666.98, + "gen_feat_1": 501.07, + "gen_feat_2": 0.506814, + "gen_feat_3": 489.44 + } + }, + { + "id": "t_movie_gen_77", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.76, + "time": 130.95, + "distance": 1675.39, + "gen_feat_1": 513.23, + "gen_feat_2": 0.496512, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_movie_gen_78", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.99, + "time": 132.12, + "distance": 1674.54, + "gen_feat_1": 495.99, + "gen_feat_2": 0.496439, + "gen_feat_3": 506.49 + } + }, + { + "id": "t_movie_gen_79", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.84, + "time": 132.9, + "distance": 1698.58, + "gen_feat_1": 486.83, + "gen_feat_2": 0.487385, + "gen_feat_3": 489.3 + } + }, + { + "id": "t_movie_gen_80", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 135.25, + "distance": 1703.48, + "gen_feat_1": 497.71, + "gen_feat_2": 0.506091, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_movie_gen_81", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.08, + "time": 138.34, + "distance": 1706.78, + "gen_feat_1": 501.18, + "gen_feat_2": 0.503416, + "gen_feat_3": 493.11 + } + }, + { + "id": "t_movie_gen_82", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.95, + "time": 132.28, + "distance": 1658.35, + "gen_feat_1": 488.13, + "gen_feat_2": 0.514958, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_83", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 135.04, + "distance": 1663.79, + "gen_feat_1": 495.07, + "gen_feat_2": 0.489223, + "gen_feat_3": 514.52 + } + }, + { + "id": "t_movie_gen_84", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.76, + "time": 137.41, + "distance": 1703.65, + "gen_feat_1": 504.9, + "gen_feat_2": 0.503529, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_movie_gen_85", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.08, + "time": 135.55, + "distance": 1691.79, + "gen_feat_1": 503.38, + "gen_feat_2": 0.5004, + "gen_feat_3": 510.63 + } + }, + { + "id": "t_movie_gen_86", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.24, + "time": 133.11, + "distance": 1689.53, + "gen_feat_1": 509.79, + "gen_feat_2": 0.49881, + "gen_feat_3": 488.86 + } + }, + { + "id": "t_movie_gen_87", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.89, + "time": 137.15, + "distance": 1698.06, + "gen_feat_1": 503.82, + "gen_feat_2": 0.50464, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_88", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.13, + "time": 131.18, + "distance": 1660.59, + "gen_feat_1": 492.85, + "gen_feat_2": 0.514114, + "gen_feat_3": 513.82 + } + }, + { + "id": "t_movie_gen_89", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.87, + "time": 135.02, + "distance": 1741.57, + "gen_feat_1": 501.92, + "gen_feat_2": 0.508398, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_90", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.28, + "time": 137.35, + "distance": 1718.09, + "gen_feat_1": 488.68, + "gen_feat_2": 0.49537, + "gen_feat_3": 493.95 + } + }, + { + "id": "t_movie_gen_91", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 137.3, + "distance": 1693.34, + "gen_feat_1": 493.19, + "gen_feat_2": 0.495672, + "gen_feat_3": 488.25 + } + }, + { + "id": "t_movie_gen_92", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.83, + "time": 137.58, + "distance": 1744.3, + "gen_feat_1": 491.56, + "gen_feat_2": 0.498387, + "gen_feat_3": 511.69 + } + }, + { + "id": "t_movie_gen_93", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.91, + "time": 133.34, + "distance": 1702.93, + "gen_feat_1": 488.01, + "gen_feat_2": 0.502779, + "gen_feat_3": 491.18 + } + }, + { + "id": "t_movie_gen_94", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 134.1, + "distance": 1680.7, + "gen_feat_1": 497.7, + "gen_feat_2": 0.497436, + "gen_feat_3": 502.47 + } + }, + { + "id": "t_movie_gen_95", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 136.67, + "distance": 1705.0, + "gen_feat_1": 488.28, + "gen_feat_2": 0.487878, + "gen_feat_3": 495.8 + } + }, + { + "id": "t_movie_gen_96", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.9, + "time": 134.07, + "distance": 1659.49, + "gen_feat_1": 492.47, + "gen_feat_2": 0.492451, + "gen_feat_3": 511.78 + } + }, + { + "id": "t_movie_gen_97", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.21, + "time": 134.31, + "distance": 1734.61, + "gen_feat_1": 493.2, + "gen_feat_2": 0.488477, + "gen_feat_3": 503.93 + } + }, + { + "id": "t_movie_gen_98", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 135.67, + "distance": 1729.26, + "gen_feat_1": 489.64, + "gen_feat_2": 0.491387, + "gen_feat_3": 506.86 + } + }, + { + "id": "t_movie_gen_99", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.79, + "time": 133.64, + "distance": 1673.71, + "gen_feat_1": 505.04, + "gen_feat_2": 0.505422, + "gen_feat_3": 513.37 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_dining", + "kind": "TASK", + "task_id": "t_dining" + }, + { + "id": "n_shopping", + "kind": "TASK", + "task_id": "t_shopping" + }, + { + "id": "n_movie", + "kind": "TASK", + "task_id": "t_movie" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "time": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "distance": { + "neutral": 0, + "compose": { + "seq": { + "fn": "MAX" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "c_within_2km", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "distance", + "op": "<=", + "value": 2000 + }, + { + "id": "c_time_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "time", + "op": "<=", + "value": 240, + "hard": false + }, + { + "id": "c_cost_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 100, + "hard": false + }, + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 50.07, + "hard": true + }, + { + "id": "gen_c_local_t_dining_time_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_dining" + ], + "attribute_id": "time", + "op": "<=", + "value": 59.79, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_dining", + "t_shopping" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_dining", + "t_movie" + ], + "hard": true + } + ], + "objective": { + "type": "MONO", + "targets": [ + "cost" + ], + "weights": { + "cost": 1.0 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/zhang2014-entertainment-planner-running-example_mono_one_soft.json b/experimentation/instances/zhang2014-entertainment-planner-running-example_mono_one_soft.json new file mode 100644 index 0000000..60bbae5 --- /dev/null +++ b/experimentation/instances/zhang2014-entertainment-planner-running-example_mono_one_soft.json @@ -0,0 +1,4531 @@ +{ + "metadata": { + "id": "zhang2014-entertainment-planner-running-example_mono_one_soft", + "name": "Personal Entertainment Planner (Zhang et al. 2014) [mono_one, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:05Z", + "description": "Modeled from the motivating example in 'Context-aware Generic Service Discovery and Service Composition' (IEEE MobServ 2014).", + "paper": { + "title": "Context-aware Generic Service Discovery and Service Composition", + "authors": "Y. Zhang et al.", + "year": 2014, + "doi": "10.1109/MobServ.2014.27" + } + }, + "features": [ + { + "id": "cost", + "name": "Total money cost (USD)", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "time", + "name": "Total time cost (minutes)", + "direction": "MINIMIZE", + "unit": "min", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1440 + } + }, + { + "id": "distance", + "name": "Distance from user's current location (meters)", + "direction": "MINIMIZE", + "unit": "m", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 50000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_rest_autre_saison", + "name": "Restaurant L’Autre Saison" + }, + { + "id": "p_cinema_banque_scotia", + "name": "Cinema Banque Scotia Montreal" + }, + { + "id": "p_seven_night_club", + "name": "Seven Night Club" + }, + { + "id": "p_local_shopping", + "name": "Local Shopping (nearby venue)" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_dining", + "name": "Restaurant / Dining activity" + }, + { + "id": "t_shopping", + "name": "Shopping activity" + }, + { + "id": "t_movie", + "name": "Movie activity" + } + ], + "candidates": [ + { + "id": "c_dining_autre_saison", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison", + "features": { + "cost": 20, + "time": 60, + "distance": 1600, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_dining_seven_night_club", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Seven Night Club", + "features": { + "cost": 20, + "time": 60, + "distance": 1800, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopping_local", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue", + "features": { + "cost": 20, + "time": 45, + "distance": 1200, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_movie_the_help_banque_scotia", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal", + "features": { + "cost": 10, + "time": 135, + "distance": 1700, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_dining_gen_1", + "task_id": "t_dining", + "provider_id": "p_gen_shared", + "name": "Dinner at Restaurant L’Autre Saison (Gen Shared)", + "features": { + "cost": 20.2, + "time": 59.79, + "distance": 1570.05, + "gen_feat_1": 508.24, + "gen_feat_2": 0.514901, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_shopping_gen_1", + "task_id": "t_shopping", + "provider_id": "p_gen_shared", + "name": "Shopping at a nearby venue (Gen Shared)", + "features": { + "cost": 19.87, + "time": 44.98, + "distance": 1189.95, + "gen_feat_1": 485.24, + "gen_feat_2": 0.486287, + "gen_feat_3": 500.42 + } + }, + { + "id": "t_movie_gen_1", + "task_id": "t_movie", + "provider_id": "p_gen_shared", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen Shared)", + "features": { + "cost": 9.82, + "time": 134.28, + "distance": 1742.9, + "gen_feat_1": 512.03, + "gen_feat_2": 0.505972, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_dining_gen_2", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.53, + "time": 59.13, + "distance": 1559.02, + "gen_feat_1": 498.66, + "gen_feat_2": 0.488957, + "gen_feat_3": 503.61 + } + }, + { + "id": "t_dining_gen_3", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.94, + "time": 58.5, + "distance": 1591.09, + "gen_feat_1": 495.96, + "gen_feat_2": 0.504969, + "gen_feat_3": 506.77 + } + }, + { + "id": "t_dining_gen_4", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.8, + "time": 61.46, + "distance": 1629.91, + "gen_feat_1": 510.53, + "gen_feat_2": 0.508, + "gen_feat_3": 491.98 + } + }, + { + "id": "t_dining_gen_5", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.22, + "time": 60.39, + "distance": 1564.48, + "gen_feat_1": 491.41, + "gen_feat_2": 0.490673, + "gen_feat_3": 490.61 + } + }, + { + "id": "t_dining_gen_6", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.38, + "time": 58.67, + "distance": 1626.15, + "gen_feat_1": 488.5, + "gen_feat_2": 0.49348, + "gen_feat_3": 495.75 + } + }, + { + "id": "t_dining_gen_7", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.18, + "time": 60.72, + "distance": 1555.22, + "gen_feat_1": 505.8, + "gen_feat_2": 0.506719, + "gen_feat_3": 499.33 + } + }, + { + "id": "t_dining_gen_8", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.43, + "time": 59.64, + "distance": 1598.13, + "gen_feat_1": 503.89, + "gen_feat_2": 0.506945, + "gen_feat_3": 508.17 + } + }, + { + "id": "t_dining_gen_9", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.64, + "time": 60.54, + "distance": 1604.33, + "gen_feat_1": 486.84, + "gen_feat_2": 0.506628, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_dining_gen_10", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 60.17, + "distance": 1616.85, + "gen_feat_1": 507.44, + "gen_feat_2": 0.489997, + "gen_feat_3": 502.16 + } + }, + { + "id": "t_dining_gen_11", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.68, + "time": 59.16, + "distance": 1620.42, + "gen_feat_1": 507.98, + "gen_feat_2": 0.488942, + "gen_feat_3": 489.19 + } + }, + { + "id": "t_dining_gen_12", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.74, + "time": 59.04, + "distance": 1602.16, + "gen_feat_1": 504.58, + "gen_feat_2": 0.489389, + "gen_feat_3": 507.41 + } + }, + { + "id": "t_dining_gen_13", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.47, + "time": 58.89, + "distance": 1622.97, + "gen_feat_1": 492.31, + "gen_feat_2": 0.503154, + "gen_feat_3": 508.55 + } + }, + { + "id": "t_dining_gen_14", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.72, + "time": 58.91, + "distance": 1626.35, + "gen_feat_1": 509.41, + "gen_feat_2": 0.490291, + "gen_feat_3": 514.74 + } + }, + { + "id": "t_dining_gen_15", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.59, + "time": 60.67, + "distance": 1631.73, + "gen_feat_1": 493.43, + "gen_feat_2": 0.498961, + "gen_feat_3": 492.15 + } + }, + { + "id": "t_dining_gen_16", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.21, + "time": 59.57, + "distance": 1621.68, + "gen_feat_1": 502.04, + "gen_feat_2": 0.491944, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_dining_gen_17", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.33, + "time": 59.99, + "distance": 1602.82, + "gen_feat_1": 513.49, + "gen_feat_2": 0.510425, + "gen_feat_3": 506.46 + } + }, + { + "id": "t_dining_gen_18", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.02, + "time": 60.13, + "distance": 1639.2, + "gen_feat_1": 498.4, + "gen_feat_2": 0.499582, + "gen_feat_3": 504.62 + } + }, + { + "id": "t_dining_gen_19", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.03, + "time": 60.73, + "distance": 1642.13, + "gen_feat_1": 507.63, + "gen_feat_2": 0.500514, + "gen_feat_3": 495.73 + } + }, + { + "id": "t_dining_gen_20", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.33, + "time": 59.96, + "distance": 1568.96, + "gen_feat_1": 488.36, + "gen_feat_2": 0.514752, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_dining_gen_21", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.8, + "time": 58.42, + "distance": 1555.46, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486429, + "gen_feat_3": 488.41 + } + }, + { + "id": "t_dining_gen_22", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.66, + "time": 61.62, + "distance": 1580.67, + "gen_feat_1": 491.06, + "gen_feat_2": 0.506184, + "gen_feat_3": 501.23 + } + }, + { + "id": "t_dining_gen_23", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.42, + "time": 61.78, + "distance": 1622.72, + "gen_feat_1": 490.83, + "gen_feat_2": 0.489949, + "gen_feat_3": 487.73 + } + }, + { + "id": "t_dining_gen_24", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.71, + "time": 59.51, + "distance": 1580.85, + "gen_feat_1": 501.15, + "gen_feat_2": 0.50297, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_25", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.42, + "time": 61.41, + "distance": 1578.66, + "gen_feat_1": 507.39, + "gen_feat_2": 0.499268, + "gen_feat_3": 490.28 + } + }, + { + "id": "t_dining_gen_26", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.55, + "time": 58.26, + "distance": 1560.85, + "gen_feat_1": 492.17, + "gen_feat_2": 0.492399, + "gen_feat_3": 511.94 + } + }, + { + "id": "t_dining_gen_27", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.48, + "time": 58.34, + "distance": 1631.2, + "gen_feat_1": 498.39, + "gen_feat_2": 0.490821, + "gen_feat_3": 491.03 + } + }, + { + "id": "t_dining_gen_28", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.04, + "time": 61.28, + "distance": 1606.8, + "gen_feat_1": 512.73, + "gen_feat_2": 0.509267, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_dining_gen_29", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.76, + "time": 60.3, + "distance": 1569.61, + "gen_feat_1": 490.22, + "gen_feat_2": 0.496831, + "gen_feat_3": 496.53 + } + }, + { + "id": "t_dining_gen_30", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.71, + "time": 60.3, + "distance": 1623.3, + "gen_feat_1": 500.21, + "gen_feat_2": 0.496569, + "gen_feat_3": 498.99 + } + }, + { + "id": "t_dining_gen_31", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.86, + "time": 59.05, + "distance": 1588.58, + "gen_feat_1": 485.96, + "gen_feat_2": 0.512749, + "gen_feat_3": 498.55 + } + }, + { + "id": "t_dining_gen_32", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.8, + "time": 59.8, + "distance": 1560.3, + "gen_feat_1": 512.24, + "gen_feat_2": 0.486102, + "gen_feat_3": 508.8 + } + }, + { + "id": "t_dining_gen_33", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.49, + "time": 61.12, + "distance": 1612.82, + "gen_feat_1": 506.05, + "gen_feat_2": 0.504153, + "gen_feat_3": 510.28 + } + }, + { + "id": "t_dining_gen_34", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.66, + "time": 58.74, + "distance": 1627.51, + "gen_feat_1": 494.47, + "gen_feat_2": 0.509322, + "gen_feat_3": 485.53 + } + }, + { + "id": "t_dining_gen_35", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.14, + "time": 60.57, + "distance": 1626.08, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513739, + "gen_feat_3": 510.69 + } + }, + { + "id": "t_dining_gen_36", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.57, + "time": 58.38, + "distance": 1610.88, + "gen_feat_1": 495.23, + "gen_feat_2": 0.509726, + "gen_feat_3": 512.08 + } + }, + { + "id": "t_dining_gen_37", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.41, + "distance": 1575.46, + "gen_feat_1": 512.15, + "gen_feat_2": 0.492042, + "gen_feat_3": 505.13 + } + }, + { + "id": "t_dining_gen_38", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.22, + "time": 59.29, + "distance": 1557.64, + "gen_feat_1": 489.83, + "gen_feat_2": 0.49146, + "gen_feat_3": 495.3 + } + }, + { + "id": "t_dining_gen_39", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.59, + "time": 61.53, + "distance": 1562.65, + "gen_feat_1": 495.8, + "gen_feat_2": 0.496923, + "gen_feat_3": 507.91 + } + }, + { + "id": "t_dining_gen_40", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.43, + "time": 60.01, + "distance": 1604.0, + "gen_feat_1": 500.49, + "gen_feat_2": 0.514685, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_41", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.58, + "time": 60.72, + "distance": 1645.52, + "gen_feat_1": 487.19, + "gen_feat_2": 0.508959, + "gen_feat_3": 497.39 + } + }, + { + "id": "t_dining_gen_42", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.2, + "time": 59.26, + "distance": 1581.92, + "gen_feat_1": 509.7, + "gen_feat_2": 0.513201, + "gen_feat_3": 491.13 + } + }, + { + "id": "t_dining_gen_43", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.45, + "time": 60.26, + "distance": 1568.18, + "gen_feat_1": 493.86, + "gen_feat_2": 0.514555, + "gen_feat_3": 489.48 + } + }, + { + "id": "t_dining_gen_44", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.58, + "time": 58.5, + "distance": 1617.8, + "gen_feat_1": 491.08, + "gen_feat_2": 0.513671, + "gen_feat_3": 486.88 + } + }, + { + "id": "t_dining_gen_45", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.68, + "time": 61.23, + "distance": 1579.97, + "gen_feat_1": 509.82, + "gen_feat_2": 0.504088, + "gen_feat_3": 512.95 + } + }, + { + "id": "t_dining_gen_46", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 60.56, + "distance": 1641.45, + "gen_feat_1": 499.89, + "gen_feat_2": 0.510488, + "gen_feat_3": 491.3 + } + }, + { + "id": "t_dining_gen_47", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.94, + "time": 58.84, + "distance": 1629.37, + "gen_feat_1": 494.2, + "gen_feat_2": 0.49711, + "gen_feat_3": 496.8 + } + }, + { + "id": "t_dining_gen_48", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.23, + "time": 58.97, + "distance": 1607.14, + "gen_feat_1": 485.39, + "gen_feat_2": 0.485086, + "gen_feat_3": 504.57 + } + }, + { + "id": "t_dining_gen_49", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.47, + "time": 59.57, + "distance": 1615.57, + "gen_feat_1": 495.03, + "gen_feat_2": 0.503496, + "gen_feat_3": 509.51 + } + }, + { + "id": "t_dining_gen_50", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.7, + "distance": 1583.69, + "gen_feat_1": 489.31, + "gen_feat_2": 0.498993, + "gen_feat_3": 498.25 + } + }, + { + "id": "t_dining_gen_51", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.06, + "time": 60.11, + "distance": 1630.7, + "gen_feat_1": 507.83, + "gen_feat_2": 0.497927, + "gen_feat_3": 485.62 + } + }, + { + "id": "t_dining_gen_52", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.53, + "time": 58.59, + "distance": 1646.13, + "gen_feat_1": 489.54, + "gen_feat_2": 0.503777, + "gen_feat_3": 487.65 + } + }, + { + "id": "t_dining_gen_53", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.9, + "time": 58.5, + "distance": 1634.44, + "gen_feat_1": 514.43, + "gen_feat_2": 0.508093, + "gen_feat_3": 499.44 + } + }, + { + "id": "t_dining_gen_54", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.18, + "time": 58.68, + "distance": 1576.83, + "gen_feat_1": 491.93, + "gen_feat_2": 0.485409, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_dining_gen_55", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.0, + "distance": 1581.79, + "gen_feat_1": 489.92, + "gen_feat_2": 0.49016, + "gen_feat_3": 513.4 + } + }, + { + "id": "t_dining_gen_56", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.18, + "time": 61.73, + "distance": 1637.68, + "gen_feat_1": 492.48, + "gen_feat_2": 0.497966, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_dining_gen_57", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.2, + "time": 61.78, + "distance": 1646.08, + "gen_feat_1": 508.92, + "gen_feat_2": 0.500426, + "gen_feat_3": 499.7 + } + }, + { + "id": "t_dining_gen_58", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.57, + "time": 59.32, + "distance": 1580.58, + "gen_feat_1": 509.74, + "gen_feat_2": 0.510379, + "gen_feat_3": 512.86 + } + }, + { + "id": "t_dining_gen_59", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.54, + "time": 59.3, + "distance": 1570.05, + "gen_feat_1": 486.4, + "gen_feat_2": 0.503502, + "gen_feat_3": 498.65 + } + }, + { + "id": "t_dining_gen_60", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.18, + "time": 61.43, + "distance": 1636.11, + "gen_feat_1": 485.66, + "gen_feat_2": 0.498532, + "gen_feat_3": 506.32 + } + }, + { + "id": "t_dining_gen_61", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.01, + "time": 59.61, + "distance": 1626.73, + "gen_feat_1": 507.2, + "gen_feat_2": 0.505098, + "gen_feat_3": 499.85 + } + }, + { + "id": "t_dining_gen_62", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.22, + "time": 59.78, + "distance": 1646.36, + "gen_feat_1": 500.64, + "gen_feat_2": 0.500049, + "gen_feat_3": 504.88 + } + }, + { + "id": "t_dining_gen_63", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.11, + "time": 59.7, + "distance": 1621.52, + "gen_feat_1": 494.18, + "gen_feat_2": 0.498313, + "gen_feat_3": 506.17 + } + }, + { + "id": "t_dining_gen_64", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.71, + "time": 61.36, + "distance": 1568.12, + "gen_feat_1": 493.75, + "gen_feat_2": 0.505406, + "gen_feat_3": 512.82 + } + }, + { + "id": "t_dining_gen_65", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.4, + "time": 58.28, + "distance": 1604.89, + "gen_feat_1": 487.06, + "gen_feat_2": 0.502445, + "gen_feat_3": 511.12 + } + }, + { + "id": "t_dining_gen_66", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 59.57, + "distance": 1581.66, + "gen_feat_1": 513.25, + "gen_feat_2": 0.493068, + "gen_feat_3": 505.54 + } + }, + { + "id": "t_dining_gen_67", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.21, + "time": 60.81, + "distance": 1606.42, + "gen_feat_1": 493.36, + "gen_feat_2": 0.50459, + "gen_feat_3": 493.01 + } + }, + { + "id": "t_dining_gen_68", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 59.09, + "distance": 1611.43, + "gen_feat_1": 505.83, + "gen_feat_2": 0.502644, + "gen_feat_3": 504.4 + } + }, + { + "id": "t_dining_gen_69", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.92, + "time": 61.04, + "distance": 1579.9, + "gen_feat_1": 512.7, + "gen_feat_2": 0.488813, + "gen_feat_3": 500.85 + } + }, + { + "id": "t_dining_gen_70", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.74, + "time": 59.83, + "distance": 1615.86, + "gen_feat_1": 505.67, + "gen_feat_2": 0.48967, + "gen_feat_3": 503.59 + } + }, + { + "id": "t_dining_gen_71", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 61.74, + "distance": 1585.25, + "gen_feat_1": 495.74, + "gen_feat_2": 0.490106, + "gen_feat_3": 499.93 + } + }, + { + "id": "t_dining_gen_72", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.9, + "time": 58.61, + "distance": 1604.96, + "gen_feat_1": 509.49, + "gen_feat_2": 0.512456, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_73", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.41, + "time": 59.23, + "distance": 1631.69, + "gen_feat_1": 507.39, + "gen_feat_2": 0.504155, + "gen_feat_3": 514.37 + } + }, + { + "id": "t_dining_gen_74", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.5, + "time": 58.7, + "distance": 1628.56, + "gen_feat_1": 514.96, + "gen_feat_2": 0.498875, + "gen_feat_3": 512.16 + } + }, + { + "id": "t_dining_gen_75", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.83, + "time": 61.78, + "distance": 1589.19, + "gen_feat_1": 501.13, + "gen_feat_2": 0.504679, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_dining_gen_76", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.02, + "time": 61.78, + "distance": 1596.36, + "gen_feat_1": 511.57, + "gen_feat_2": 0.51185, + "gen_feat_3": 493.99 + } + }, + { + "id": "t_dining_gen_77", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.38, + "time": 59.52, + "distance": 1573.49, + "gen_feat_1": 513.61, + "gen_feat_2": 0.50886, + "gen_feat_3": 505.08 + } + }, + { + "id": "t_dining_gen_78", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.28, + "time": 59.03, + "distance": 1628.26, + "gen_feat_1": 513.77, + "gen_feat_2": 0.508209, + "gen_feat_3": 504.63 + } + }, + { + "id": "t_dining_gen_79", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.75, + "time": 60.98, + "distance": 1603.39, + "gen_feat_1": 510.74, + "gen_feat_2": 0.51442, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_dining_gen_80", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.34, + "time": 59.39, + "distance": 1607.15, + "gen_feat_1": 489.01, + "gen_feat_2": 0.508841, + "gen_feat_3": 503.65 + } + }, + { + "id": "t_dining_gen_81", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.78, + "time": 61.32, + "distance": 1606.79, + "gen_feat_1": 494.77, + "gen_feat_2": 0.498081, + "gen_feat_3": 490.68 + } + }, + { + "id": "t_dining_gen_82", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.0, + "time": 60.47, + "distance": 1578.03, + "gen_feat_1": 505.85, + "gen_feat_2": 0.496498, + "gen_feat_3": 494.3 + } + }, + { + "id": "t_dining_gen_83", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.59, + "time": 60.4, + "distance": 1576.41, + "gen_feat_1": 487.54, + "gen_feat_2": 0.490813, + "gen_feat_3": 506.97 + } + }, + { + "id": "t_dining_gen_84", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.45, + "time": 58.59, + "distance": 1635.41, + "gen_feat_1": 507.53, + "gen_feat_2": 0.499359, + "gen_feat_3": 511.49 + } + }, + { + "id": "t_dining_gen_85", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.55, + "time": 59.37, + "distance": 1578.95, + "gen_feat_1": 500.14, + "gen_feat_2": 0.504331, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_dining_gen_86", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.11, + "distance": 1556.1, + "gen_feat_1": 513.36, + "gen_feat_2": 0.512958, + "gen_feat_3": 493.44 + } + }, + { + "id": "t_dining_gen_87", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.26, + "time": 59.23, + "distance": 1563.62, + "gen_feat_1": 489.36, + "gen_feat_2": 0.51222, + "gen_feat_3": 503.86 + } + }, + { + "id": "t_dining_gen_88", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.46, + "time": 61.2, + "distance": 1588.14, + "gen_feat_1": 488.89, + "gen_feat_2": 0.496175, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_dining_gen_89", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.79, + "time": 58.63, + "distance": 1622.85, + "gen_feat_1": 512.62, + "gen_feat_2": 0.485995, + "gen_feat_3": 487.83 + } + }, + { + "id": "t_dining_gen_90", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.48, + "time": 58.69, + "distance": 1640.49, + "gen_feat_1": 511.37, + "gen_feat_2": 0.494218, + "gen_feat_3": 505.83 + } + }, + { + "id": "t_dining_gen_91", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.58, + "time": 58.72, + "distance": 1630.9, + "gen_feat_1": 505.33, + "gen_feat_2": 0.485446, + "gen_feat_3": 496.64 + } + }, + { + "id": "t_dining_gen_92", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.04, + "time": 59.56, + "distance": 1559.07, + "gen_feat_1": 491.21, + "gen_feat_2": 0.509726, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_93", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.84, + "time": 60.45, + "distance": 1596.68, + "gen_feat_1": 493.98, + "gen_feat_2": 0.489239, + "gen_feat_3": 493.56 + } + }, + { + "id": "t_dining_gen_94", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.56, + "time": 59.95, + "distance": 1630.28, + "gen_feat_1": 488.49, + "gen_feat_2": 0.505218, + "gen_feat_3": 491.42 + } + }, + { + "id": "t_dining_gen_95", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.97, + "time": 59.51, + "distance": 1593.3, + "gen_feat_1": 488.66, + "gen_feat_2": 0.490214, + "gen_feat_3": 504.25 + } + }, + { + "id": "t_dining_gen_96", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.85, + "time": 58.35, + "distance": 1552.26, + "gen_feat_1": 503.49, + "gen_feat_2": 0.48523, + "gen_feat_3": 504.39 + } + }, + { + "id": "t_dining_gen_97", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.51, + "time": 59.5, + "distance": 1634.44, + "gen_feat_1": 497.31, + "gen_feat_2": 0.5107, + "gen_feat_3": 507.86 + } + }, + { + "id": "t_dining_gen_98", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.5, + "time": 61.17, + "distance": 1593.89, + "gen_feat_1": 510.31, + "gen_feat_2": 0.50078, + "gen_feat_3": 494.95 + } + }, + { + "id": "t_shopping_gen_2", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.95, + "time": 44.3, + "distance": 1198.71, + "gen_feat_1": 508.4, + "gen_feat_2": 0.485625, + "gen_feat_3": 507.99 + } + }, + { + "id": "t_shopping_gen_3", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 44.18, + "distance": 1196.21, + "gen_feat_1": 485.72, + "gen_feat_2": 0.488455, + "gen_feat_3": 489.7 + } + }, + { + "id": "t_shopping_gen_4", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.78, + "time": 44.9, + "distance": 1179.12, + "gen_feat_1": 503.26, + "gen_feat_2": 0.498291, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_shopping_gen_5", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.51, + "time": 44.53, + "distance": 1216.23, + "gen_feat_1": 510.8, + "gen_feat_2": 0.507066, + "gen_feat_3": 504.03 + } + }, + { + "id": "t_shopping_gen_6", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.18, + "time": 44.06, + "distance": 1199.34, + "gen_feat_1": 501.17, + "gen_feat_2": 0.493458, + "gen_feat_3": 510.83 + } + }, + { + "id": "t_shopping_gen_7", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.59, + "time": 45.0, + "distance": 1183.14, + "gen_feat_1": 501.56, + "gen_feat_2": 0.496232, + "gen_feat_3": 496.33 + } + }, + { + "id": "t_shopping_gen_8", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.45, + "time": 43.75, + "distance": 1196.19, + "gen_feat_1": 488.54, + "gen_feat_2": 0.508864, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_9", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.29, + "time": 45.49, + "distance": 1235.6, + "gen_feat_1": 505.19, + "gen_feat_2": 0.486447, + "gen_feat_3": 505.3 + } + }, + { + "id": "t_shopping_gen_10", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.2, + "time": 44.86, + "distance": 1227.31, + "gen_feat_1": 487.19, + "gen_feat_2": 0.512416, + "gen_feat_3": 499.73 + } + }, + { + "id": "t_shopping_gen_11", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.86, + "time": 44.51, + "distance": 1227.77, + "gen_feat_1": 488.24, + "gen_feat_2": 0.510589, + "gen_feat_3": 510.74 + } + }, + { + "id": "t_shopping_gen_12", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.87, + "time": 44.69, + "distance": 1170.61, + "gen_feat_1": 503.79, + "gen_feat_2": 0.487994, + "gen_feat_3": 485.28 + } + }, + { + "id": "t_shopping_gen_13", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.87, + "time": 46.21, + "distance": 1228.85, + "gen_feat_1": 488.6, + "gen_feat_2": 0.499239, + "gen_feat_3": 503.2 + } + }, + { + "id": "t_shopping_gen_14", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.47, + "time": 44.09, + "distance": 1191.47, + "gen_feat_1": 510.69, + "gen_feat_2": 0.500607, + "gen_feat_3": 501.94 + } + }, + { + "id": "t_shopping_gen_15", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.91, + "time": 44.79, + "distance": 1194.44, + "gen_feat_1": 493.04, + "gen_feat_2": 0.493381, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_16", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.74, + "time": 45.76, + "distance": 1214.32, + "gen_feat_1": 508.04, + "gen_feat_2": 0.505849, + "gen_feat_3": 514.42 + } + }, + { + "id": "t_shopping_gen_17", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.56, + "time": 44.53, + "distance": 1186.46, + "gen_feat_1": 497.1, + "gen_feat_2": 0.507483, + "gen_feat_3": 487.33 + } + }, + { + "id": "t_shopping_gen_18", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.3, + "time": 46.02, + "distance": 1191.93, + "gen_feat_1": 502.5, + "gen_feat_2": 0.489832, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_shopping_gen_19", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.29, + "time": 44.76, + "distance": 1178.65, + "gen_feat_1": 486.31, + "gen_feat_2": 0.501927, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_shopping_gen_20", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.59, + "time": 45.62, + "distance": 1234.59, + "gen_feat_1": 508.23, + "gen_feat_2": 0.488622, + "gen_feat_3": 505.15 + } + }, + { + "id": "t_shopping_gen_21", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.41, + "time": 44.06, + "distance": 1185.1, + "gen_feat_1": 498.37, + "gen_feat_2": 0.491076, + "gen_feat_3": 502.07 + } + }, + { + "id": "t_shopping_gen_22", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.07, + "time": 45.23, + "distance": 1172.35, + "gen_feat_1": 489.15, + "gen_feat_2": 0.487341, + "gen_feat_3": 502.22 + } + }, + { + "id": "t_shopping_gen_23", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.07, + "time": 44.11, + "distance": 1228.63, + "gen_feat_1": 489.68, + "gen_feat_2": 0.497214, + "gen_feat_3": 510.3 + } + }, + { + "id": "t_shopping_gen_24", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.79, + "time": 45.29, + "distance": 1211.47, + "gen_feat_1": 513.99, + "gen_feat_2": 0.511272, + "gen_feat_3": 512.18 + } + }, + { + "id": "t_shopping_gen_25", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.49, + "time": 45.68, + "distance": 1197.16, + "gen_feat_1": 504.19, + "gen_feat_2": 0.507954, + "gen_feat_3": 509.7 + } + }, + { + "id": "t_shopping_gen_26", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.61, + "time": 45.73, + "distance": 1191.91, + "gen_feat_1": 499.13, + "gen_feat_2": 0.502797, + "gen_feat_3": 486.18 + } + }, + { + "id": "t_shopping_gen_27", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.64, + "time": 45.28, + "distance": 1176.71, + "gen_feat_1": 505.64, + "gen_feat_2": 0.491227, + "gen_feat_3": 508.35 + } + }, + { + "id": "t_shopping_gen_28", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.87, + "time": 45.0, + "distance": 1216.17, + "gen_feat_1": 500.61, + "gen_feat_2": 0.512609, + "gen_feat_3": 509.87 + } + }, + { + "id": "t_shopping_gen_29", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.37, + "time": 44.26, + "distance": 1180.24, + "gen_feat_1": 487.72, + "gen_feat_2": 0.485295, + "gen_feat_3": 487.2 + } + }, + { + "id": "t_shopping_gen_30", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.65, + "time": 44.57, + "distance": 1197.12, + "gen_feat_1": 500.2, + "gen_feat_2": 0.506494, + "gen_feat_3": 511.02 + } + }, + { + "id": "t_shopping_gen_31", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.54, + "time": 43.79, + "distance": 1190.28, + "gen_feat_1": 501.09, + "gen_feat_2": 0.496883, + "gen_feat_3": 504.0 + } + }, + { + "id": "t_shopping_gen_32", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.4, + "time": 44.15, + "distance": 1210.36, + "gen_feat_1": 506.65, + "gen_feat_2": 0.494619, + "gen_feat_3": 489.54 + } + }, + { + "id": "t_shopping_gen_33", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.78, + "time": 44.05, + "distance": 1224.7, + "gen_feat_1": 505.11, + "gen_feat_2": 0.497586, + "gen_feat_3": 502.56 + } + }, + { + "id": "t_shopping_gen_34", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.93, + "time": 45.15, + "distance": 1219.85, + "gen_feat_1": 498.34, + "gen_feat_2": 0.488983, + "gen_feat_3": 494.13 + } + }, + { + "id": "t_shopping_gen_35", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.82, + "time": 44.55, + "distance": 1224.73, + "gen_feat_1": 511.51, + "gen_feat_2": 0.504196, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_shopping_gen_36", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.86, + "time": 45.5, + "distance": 1196.08, + "gen_feat_1": 495.33, + "gen_feat_2": 0.498326, + "gen_feat_3": 486.34 + } + }, + { + "id": "t_shopping_gen_37", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.59, + "time": 44.26, + "distance": 1203.59, + "gen_feat_1": 496.81, + "gen_feat_2": 0.510331, + "gen_feat_3": 506.27 + } + }, + { + "id": "t_shopping_gen_38", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.92, + "time": 45.08, + "distance": 1203.94, + "gen_feat_1": 500.75, + "gen_feat_2": 0.49117, + "gen_feat_3": 491.78 + } + }, + { + "id": "t_shopping_gen_39", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.31, + "time": 46.16, + "distance": 1182.79, + "gen_feat_1": 497.1, + "gen_feat_2": 0.497946, + "gen_feat_3": 512.02 + } + }, + { + "id": "t_shopping_gen_40", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.54, + "time": 44.22, + "distance": 1217.58, + "gen_feat_1": 514.19, + "gen_feat_2": 0.507653, + "gen_feat_3": 502.34 + } + }, + { + "id": "t_shopping_gen_41", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.64, + "time": 44.32, + "distance": 1196.64, + "gen_feat_1": 510.6, + "gen_feat_2": 0.510227, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_42", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.93, + "time": 46.08, + "distance": 1215.22, + "gen_feat_1": 509.33, + "gen_feat_2": 0.489128, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_43", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.94, + "time": 46.06, + "distance": 1197.83, + "gen_feat_1": 494.23, + "gen_feat_2": 0.491429, + "gen_feat_3": 512.77 + } + }, + { + "id": "t_shopping_gen_44", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.62, + "time": 44.6, + "distance": 1228.92, + "gen_feat_1": 503.07, + "gen_feat_2": 0.497061, + "gen_feat_3": 508.73 + } + }, + { + "id": "t_shopping_gen_45", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.54, + "time": 45.8, + "distance": 1230.3, + "gen_feat_1": 498.44, + "gen_feat_2": 0.491182, + "gen_feat_3": 510.12 + } + }, + { + "id": "t_shopping_gen_46", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 44.28, + "distance": 1216.64, + "gen_feat_1": 488.95, + "gen_feat_2": 0.485686, + "gen_feat_3": 513.45 + } + }, + { + "id": "t_shopping_gen_47", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.4, + "time": 44.8, + "distance": 1210.54, + "gen_feat_1": 488.83, + "gen_feat_2": 0.508023, + "gen_feat_3": 485.22 + } + }, + { + "id": "t_shopping_gen_48", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.69, + "time": 44.94, + "distance": 1204.74, + "gen_feat_1": 504.02, + "gen_feat_2": 0.485166, + "gen_feat_3": 509.28 + } + }, + { + "id": "t_shopping_gen_49", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.63, + "time": 45.76, + "distance": 1234.29, + "gen_feat_1": 496.66, + "gen_feat_2": 0.510271, + "gen_feat_3": 488.57 + } + }, + { + "id": "t_shopping_gen_50", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.54, + "time": 44.91, + "distance": 1215.96, + "gen_feat_1": 509.77, + "gen_feat_2": 0.485673, + "gen_feat_3": 502.33 + } + }, + { + "id": "t_shopping_gen_51", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.48, + "time": 46.17, + "distance": 1186.08, + "gen_feat_1": 512.11, + "gen_feat_2": 0.491803, + "gen_feat_3": 503.47 + } + }, + { + "id": "t_shopping_gen_52", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.89, + "time": 44.45, + "distance": 1194.92, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486916, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_shopping_gen_53", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.35, + "time": 44.61, + "distance": 1191.25, + "gen_feat_1": 503.61, + "gen_feat_2": 0.493221, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_shopping_gen_54", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.73, + "time": 45.54, + "distance": 1223.55, + "gen_feat_1": 494.27, + "gen_feat_2": 0.490001, + "gen_feat_3": 493.72 + } + }, + { + "id": "t_shopping_gen_55", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 44.24, + "distance": 1228.06, + "gen_feat_1": 497.25, + "gen_feat_2": 0.49955, + "gen_feat_3": 486.14 + } + }, + { + "id": "t_shopping_gen_56", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.69, + "time": 44.04, + "distance": 1224.5, + "gen_feat_1": 492.29, + "gen_feat_2": 0.500032, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_57", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.68, + "time": 46.32, + "distance": 1227.05, + "gen_feat_1": 510.63, + "gen_feat_2": 0.51217, + "gen_feat_3": 489.8 + } + }, + { + "id": "t_shopping_gen_58", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.13, + "time": 45.42, + "distance": 1231.38, + "gen_feat_1": 499.25, + "gen_feat_2": 0.502657, + "gen_feat_3": 488.16 + } + }, + { + "id": "t_shopping_gen_59", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 45.04, + "distance": 1206.58, + "gen_feat_1": 488.66, + "gen_feat_2": 0.500622, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_shopping_gen_60", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.33, + "time": 46.0, + "distance": 1170.11, + "gen_feat_1": 511.4, + "gen_feat_2": 0.49549, + "gen_feat_3": 503.71 + } + }, + { + "id": "t_shopping_gen_61", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.18, + "time": 46.1, + "distance": 1190.97, + "gen_feat_1": 498.6, + "gen_feat_2": 0.501812, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_62", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.24, + "time": 45.7, + "distance": 1164.26, + "gen_feat_1": 485.26, + "gen_feat_2": 0.49031, + "gen_feat_3": 487.45 + } + }, + { + "id": "t_shopping_gen_63", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.17, + "time": 45.97, + "distance": 1190.2, + "gen_feat_1": 511.28, + "gen_feat_2": 0.51432, + "gen_feat_3": 513.58 + } + }, + { + "id": "t_shopping_gen_64", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.73, + "time": 44.03, + "distance": 1178.97, + "gen_feat_1": 487.49, + "gen_feat_2": 0.508632, + "gen_feat_3": 500.21 + } + }, + { + "id": "t_shopping_gen_65", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.67, + "time": 43.83, + "distance": 1176.27, + "gen_feat_1": 512.03, + "gen_feat_2": 0.49815, + "gen_feat_3": 501.03 + } + }, + { + "id": "t_shopping_gen_66", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.26, + "time": 44.73, + "distance": 1220.07, + "gen_feat_1": 504.64, + "gen_feat_2": 0.502789, + "gen_feat_3": 505.95 + } + }, + { + "id": "t_shopping_gen_67", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.81, + "time": 44.73, + "distance": 1180.99, + "gen_feat_1": 491.13, + "gen_feat_2": 0.488945, + "gen_feat_3": 487.4 + } + }, + { + "id": "t_shopping_gen_68", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.86, + "time": 43.67, + "distance": 1232.56, + "gen_feat_1": 512.67, + "gen_feat_2": 0.491258, + "gen_feat_3": 495.53 + } + }, + { + "id": "t_shopping_gen_69", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.0, + "time": 45.32, + "distance": 1179.79, + "gen_feat_1": 504.7, + "gen_feat_2": 0.501825, + "gen_feat_3": 494.35 + } + }, + { + "id": "t_shopping_gen_70", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 45.99, + "distance": 1206.39, + "gen_feat_1": 497.84, + "gen_feat_2": 0.509326, + "gen_feat_3": 508.37 + } + }, + { + "id": "t_shopping_gen_71", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.89, + "time": 44.23, + "distance": 1211.83, + "gen_feat_1": 489.02, + "gen_feat_2": 0.504569, + "gen_feat_3": 486.74 + } + }, + { + "id": "t_shopping_gen_72", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.25, + "time": 43.89, + "distance": 1218.83, + "gen_feat_1": 514.57, + "gen_feat_2": 0.487312, + "gen_feat_3": 491.96 + } + }, + { + "id": "t_shopping_gen_73", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 45.64, + "distance": 1171.76, + "gen_feat_1": 499.58, + "gen_feat_2": 0.499353, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_shopping_gen_74", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.51, + "time": 45.18, + "distance": 1235.16, + "gen_feat_1": 491.35, + "gen_feat_2": 0.488032, + "gen_feat_3": 508.76 + } + }, + { + "id": "t_shopping_gen_75", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.45, + "time": 45.29, + "distance": 1185.87, + "gen_feat_1": 506.16, + "gen_feat_2": 0.494622, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_shopping_gen_76", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.11, + "time": 44.39, + "distance": 1222.53, + "gen_feat_1": 507.53, + "gen_feat_2": 0.505002, + "gen_feat_3": 503.01 + } + }, + { + "id": "t_shopping_gen_77", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.93, + "time": 46.13, + "distance": 1210.75, + "gen_feat_1": 506.27, + "gen_feat_2": 0.505682, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_shopping_gen_78", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.16, + "time": 46.07, + "distance": 1210.7, + "gen_feat_1": 508.56, + "gen_feat_2": 0.487189, + "gen_feat_3": 504.12 + } + }, + { + "id": "t_shopping_gen_79", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.03, + "time": 45.66, + "distance": 1190.96, + "gen_feat_1": 489.72, + "gen_feat_2": 0.488214, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_shopping_gen_80", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.77, + "time": 45.73, + "distance": 1226.46, + "gen_feat_1": 498.85, + "gen_feat_2": 0.50612, + "gen_feat_3": 508.83 + } + }, + { + "id": "t_shopping_gen_81", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.19, + "time": 44.4, + "distance": 1207.41, + "gen_feat_1": 512.69, + "gen_feat_2": 0.49773, + "gen_feat_3": 499.57 + } + }, + { + "id": "t_shopping_gen_82", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.91, + "time": 45.81, + "distance": 1232.14, + "gen_feat_1": 501.37, + "gen_feat_2": 0.501413, + "gen_feat_3": 509.02 + } + }, + { + "id": "t_shopping_gen_83", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.46, + "time": 45.7, + "distance": 1201.06, + "gen_feat_1": 507.37, + "gen_feat_2": 0.512514, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_84", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.46, + "time": 45.7, + "distance": 1176.63, + "gen_feat_1": 500.57, + "gen_feat_2": 0.512907, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_shopping_gen_85", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.3, + "time": 44.77, + "distance": 1227.54, + "gen_feat_1": 488.72, + "gen_feat_2": 0.491267, + "gen_feat_3": 504.72 + } + }, + { + "id": "t_shopping_gen_86", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.53, + "time": 44.82, + "distance": 1227.19, + "gen_feat_1": 495.19, + "gen_feat_2": 0.506807, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_shopping_gen_87", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.76, + "time": 45.19, + "distance": 1197.27, + "gen_feat_1": 492.23, + "gen_feat_2": 0.502276, + "gen_feat_3": 497.83 + } + }, + { + "id": "t_shopping_gen_88", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.51, + "time": 46.32, + "distance": 1202.27, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500008, + "gen_feat_3": 494.37 + } + }, + { + "id": "t_shopping_gen_89", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.31, + "time": 45.09, + "distance": 1196.05, + "gen_feat_1": 488.52, + "gen_feat_2": 0.501783, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_90", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.15, + "time": 45.09, + "distance": 1187.36, + "gen_feat_1": 510.87, + "gen_feat_2": 0.48952, + "gen_feat_3": 487.44 + } + }, + { + "id": "t_shopping_gen_91", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.98, + "time": 44.28, + "distance": 1230.46, + "gen_feat_1": 494.85, + "gen_feat_2": 0.49072, + "gen_feat_3": 507.33 + } + }, + { + "id": "t_shopping_gen_92", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.46, + "time": 44.78, + "distance": 1190.65, + "gen_feat_1": 511.14, + "gen_feat_2": 0.491965, + "gen_feat_3": 510.07 + } + }, + { + "id": "t_shopping_gen_93", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 44.16, + "distance": 1232.76, + "gen_feat_1": 491.76, + "gen_feat_2": 0.49386, + "gen_feat_3": 489.99 + } + }, + { + "id": "t_shopping_gen_94", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.09, + "time": 45.07, + "distance": 1187.9, + "gen_feat_1": 500.36, + "gen_feat_2": 0.505173, + "gen_feat_3": 512.28 + } + }, + { + "id": "t_shopping_gen_95", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.29, + "time": 44.73, + "distance": 1224.17, + "gen_feat_1": 507.58, + "gen_feat_2": 0.48708, + "gen_feat_3": 511.59 + } + }, + { + "id": "t_shopping_gen_96", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.53, + "time": 43.89, + "distance": 1206.53, + "gen_feat_1": 493.71, + "gen_feat_2": 0.505153, + "gen_feat_3": 502.61 + } + }, + { + "id": "t_shopping_gen_97", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.6, + "time": 45.25, + "distance": 1198.77, + "gen_feat_1": 499.74, + "gen_feat_2": 0.499805, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_shopping_gen_98", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.94, + "time": 45.61, + "distance": 1168.51, + "gen_feat_1": 491.6, + "gen_feat_2": 0.511011, + "gen_feat_3": 491.45 + } + }, + { + "id": "t_shopping_gen_99", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.76, + "time": 45.99, + "distance": 1192.67, + "gen_feat_1": 500.07, + "gen_feat_2": 0.491787, + "gen_feat_3": 488.2 + } + }, + { + "id": "t_movie_gen_2", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.81, + "time": 138.02, + "distance": 1654.01, + "gen_feat_1": 503.91, + "gen_feat_2": 0.502664, + "gen_feat_3": 506.8 + } + }, + { + "id": "t_movie_gen_3", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.98, + "time": 133.32, + "distance": 1664.29, + "gen_feat_1": 491.47, + "gen_feat_2": 0.500325, + "gen_feat_3": 496.28 + } + }, + { + "id": "t_movie_gen_4", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.11, + "time": 136.06, + "distance": 1704.88, + "gen_feat_1": 505.19, + "gen_feat_2": 0.509953, + "gen_feat_3": 499.19 + } + }, + { + "id": "t_movie_gen_5", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.17, + "time": 136.4, + "distance": 1724.13, + "gen_feat_1": 511.77, + "gen_feat_2": 0.505076, + "gen_feat_3": 491.0 + } + }, + { + "id": "t_movie_gen_6", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.2, + "time": 137.15, + "distance": 1664.63, + "gen_feat_1": 514.48, + "gen_feat_2": 0.503771, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_movie_gen_7", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.16, + "time": 135.61, + "distance": 1726.58, + "gen_feat_1": 493.34, + "gen_feat_2": 0.493128, + "gen_feat_3": 491.4 + } + }, + { + "id": "t_movie_gen_8", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.91, + "time": 135.69, + "distance": 1678.5, + "gen_feat_1": 493.49, + "gen_feat_2": 0.506584, + "gen_feat_3": 491.95 + } + }, + { + "id": "t_movie_gen_9", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.09, + "time": 132.47, + "distance": 1682.74, + "gen_feat_1": 513.37, + "gen_feat_2": 0.496243, + "gen_feat_3": 510.52 + } + }, + { + "id": "t_movie_gen_10", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.25, + "time": 134.94, + "distance": 1683.72, + "gen_feat_1": 493.66, + "gen_feat_2": 0.502149, + "gen_feat_3": 491.38 + } + }, + { + "id": "t_movie_gen_11", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 132.2, + "distance": 1677.4, + "gen_feat_1": 513.51, + "gen_feat_2": 0.512663, + "gen_feat_3": 496.77 + } + }, + { + "id": "t_movie_gen_12", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.02, + "time": 136.12, + "distance": 1683.25, + "gen_feat_1": 486.72, + "gen_feat_2": 0.48763, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_movie_gen_13", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 131.91, + "distance": 1710.85, + "gen_feat_1": 493.33, + "gen_feat_2": 0.499006, + "gen_feat_3": 497.58 + } + }, + { + "id": "t_movie_gen_14", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.85, + "time": 137.69, + "distance": 1738.0, + "gen_feat_1": 501.65, + "gen_feat_2": 0.507629, + "gen_feat_3": 509.86 + } + }, + { + "id": "t_movie_gen_15", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.02, + "time": 133.61, + "distance": 1660.2, + "gen_feat_1": 512.64, + "gen_feat_2": 0.487548, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_movie_gen_16", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.2, + "time": 132.6, + "distance": 1669.36, + "gen_feat_1": 490.54, + "gen_feat_2": 0.507088, + "gen_feat_3": 496.37 + } + }, + { + "id": "t_movie_gen_17", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.25, + "time": 138.2, + "distance": 1711.42, + "gen_feat_1": 497.15, + "gen_feat_2": 0.513509, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_movie_gen_18", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.76, + "time": 136.31, + "distance": 1749.75, + "gen_feat_1": 514.83, + "gen_feat_2": 0.50335, + "gen_feat_3": 503.33 + } + }, + { + "id": "t_movie_gen_19", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 131.68, + "distance": 1656.52, + "gen_feat_1": 487.37, + "gen_feat_2": 0.493627, + "gen_feat_3": 508.19 + } + }, + { + "id": "t_movie_gen_20", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.9, + "time": 137.27, + "distance": 1709.53, + "gen_feat_1": 497.44, + "gen_feat_2": 0.486038, + "gen_feat_3": 502.32 + } + }, + { + "id": "t_movie_gen_21", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.83, + "time": 136.88, + "distance": 1708.94, + "gen_feat_1": 492.6, + "gen_feat_2": 0.496495, + "gen_feat_3": 490.83 + } + }, + { + "id": "t_movie_gen_22", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.12, + "time": 133.07, + "distance": 1711.62, + "gen_feat_1": 493.34, + "gen_feat_2": 0.499182, + "gen_feat_3": 499.28 + } + }, + { + "id": "t_movie_gen_23", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.12, + "time": 134.21, + "distance": 1736.25, + "gen_feat_1": 503.64, + "gen_feat_2": 0.5068, + "gen_feat_3": 489.21 + } + }, + { + "id": "t_movie_gen_24", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 132.64, + "distance": 1664.88, + "gen_feat_1": 510.09, + "gen_feat_2": 0.510289, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_movie_gen_25", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.1, + "time": 137.12, + "distance": 1701.34, + "gen_feat_1": 501.06, + "gen_feat_2": 0.49893, + "gen_feat_3": 507.73 + } + }, + { + "id": "t_movie_gen_26", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 136.45, + "distance": 1678.04, + "gen_feat_1": 494.8, + "gen_feat_2": 0.485118, + "gen_feat_3": 508.86 + } + }, + { + "id": "t_movie_gen_27", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.83, + "time": 134.67, + "distance": 1694.92, + "gen_feat_1": 503.64, + "gen_feat_2": 0.511029, + "gen_feat_3": 505.48 + } + }, + { + "id": "t_movie_gen_28", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.96, + "time": 138.62, + "distance": 1659.13, + "gen_feat_1": 491.47, + "gen_feat_2": 0.511429, + "gen_feat_3": 500.08 + } + }, + { + "id": "t_movie_gen_29", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.76, + "time": 138.64, + "distance": 1697.07, + "gen_feat_1": 498.44, + "gen_feat_2": 0.509025, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_movie_gen_30", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.39, + "distance": 1730.3, + "gen_feat_1": 510.02, + "gen_feat_2": 0.491101, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_31", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.28, + "time": 131.41, + "distance": 1685.65, + "gen_feat_1": 490.64, + "gen_feat_2": 0.485642, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_movie_gen_32", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.93, + "time": 134.98, + "distance": 1695.11, + "gen_feat_1": 501.21, + "gen_feat_2": 0.50543, + "gen_feat_3": 499.51 + } + }, + { + "id": "t_movie_gen_33", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.87, + "time": 137.83, + "distance": 1715.38, + "gen_feat_1": 513.71, + "gen_feat_2": 0.493568, + "gen_feat_3": 514.01 + } + }, + { + "id": "t_movie_gen_34", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.81, + "time": 132.4, + "distance": 1663.09, + "gen_feat_1": 506.91, + "gen_feat_2": 0.510638, + "gen_feat_3": 501.83 + } + }, + { + "id": "t_movie_gen_35", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.24, + "time": 136.79, + "distance": 1694.27, + "gen_feat_1": 510.84, + "gen_feat_2": 0.507452, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_movie_gen_36", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.16, + "time": 136.15, + "distance": 1670.24, + "gen_feat_1": 502.99, + "gen_feat_2": 0.495856, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_37", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.3, + "time": 136.48, + "distance": 1719.06, + "gen_feat_1": 512.77, + "gen_feat_2": 0.488773, + "gen_feat_3": 505.19 + } + }, + { + "id": "t_movie_gen_38", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.89, + "time": 137.8, + "distance": 1682.43, + "gen_feat_1": 514.67, + "gen_feat_2": 0.508214, + "gen_feat_3": 504.71 + } + }, + { + "id": "t_movie_gen_39", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.88, + "time": 136.94, + "distance": 1652.85, + "gen_feat_1": 499.19, + "gen_feat_2": 0.500729, + "gen_feat_3": 511.08 + } + }, + { + "id": "t_movie_gen_40", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.75, + "time": 136.81, + "distance": 1673.83, + "gen_feat_1": 510.5, + "gen_feat_2": 0.496266, + "gen_feat_3": 512.35 + } + }, + { + "id": "t_movie_gen_41", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.84, + "time": 133.13, + "distance": 1698.79, + "gen_feat_1": 504.79, + "gen_feat_2": 0.491761, + "gen_feat_3": 489.88 + } + }, + { + "id": "t_movie_gen_42", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.79, + "time": 132.71, + "distance": 1654.02, + "gen_feat_1": 488.54, + "gen_feat_2": 0.496646, + "gen_feat_3": 506.89 + } + }, + { + "id": "t_movie_gen_43", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.03, + "time": 135.73, + "distance": 1687.52, + "gen_feat_1": 489.12, + "gen_feat_2": 0.50799, + "gen_feat_3": 499.94 + } + }, + { + "id": "t_movie_gen_44", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.09, + "time": 138.68, + "distance": 1703.05, + "gen_feat_1": 510.12, + "gen_feat_2": 0.485551, + "gen_feat_3": 502.13 + } + }, + { + "id": "t_movie_gen_45", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.86, + "time": 133.42, + "distance": 1652.65, + "gen_feat_1": 488.6, + "gen_feat_2": 0.510397, + "gen_feat_3": 509.98 + } + }, + { + "id": "t_movie_gen_46", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.97, + "time": 131.94, + "distance": 1673.56, + "gen_feat_1": 486.56, + "gen_feat_2": 0.505523, + "gen_feat_3": 501.82 + } + }, + { + "id": "t_movie_gen_47", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.0, + "time": 133.55, + "distance": 1671.34, + "gen_feat_1": 488.32, + "gen_feat_2": 0.49915, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_movie_gen_48", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.06, + "time": 138.36, + "distance": 1677.66, + "gen_feat_1": 497.58, + "gen_feat_2": 0.497849, + "gen_feat_3": 488.29 + } + }, + { + "id": "t_movie_gen_49", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 133.95, + "distance": 1742.48, + "gen_feat_1": 495.5, + "gen_feat_2": 0.511503, + "gen_feat_3": 491.31 + } + }, + { + "id": "t_movie_gen_50", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.77, + "time": 135.54, + "distance": 1710.41, + "gen_feat_1": 487.97, + "gen_feat_2": 0.508317, + "gen_feat_3": 490.49 + } + }, + { + "id": "t_movie_gen_51", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.77, + "time": 135.9, + "distance": 1664.29, + "gen_feat_1": 513.14, + "gen_feat_2": 0.507714, + "gen_feat_3": 487.99 + } + }, + { + "id": "t_movie_gen_52", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.74, + "time": 133.36, + "distance": 1679.04, + "gen_feat_1": 502.14, + "gen_feat_2": 0.489374, + "gen_feat_3": 501.0 + } + }, + { + "id": "t_movie_gen_53", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.75, + "time": 137.75, + "distance": 1727.9, + "gen_feat_1": 494.43, + "gen_feat_2": 0.492795, + "gen_feat_3": 507.56 + } + }, + { + "id": "t_movie_gen_54", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 137.23, + "distance": 1749.88, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514964, + "gen_feat_3": 513.51 + } + }, + { + "id": "t_movie_gen_55", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.27, + "time": 131.7, + "distance": 1671.69, + "gen_feat_1": 491.71, + "gen_feat_2": 0.507637, + "gen_feat_3": 496.63 + } + }, + { + "id": "t_movie_gen_56", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.25, + "time": 133.82, + "distance": 1744.69, + "gen_feat_1": 513.96, + "gen_feat_2": 0.486719, + "gen_feat_3": 505.59 + } + }, + { + "id": "t_movie_gen_57", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.99, + "distance": 1687.02, + "gen_feat_1": 495.73, + "gen_feat_2": 0.497053, + "gen_feat_3": 485.08 + } + }, + { + "id": "t_movie_gen_58", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 134.0, + "distance": 1717.93, + "gen_feat_1": 498.58, + "gen_feat_2": 0.514512, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_movie_gen_59", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 135.99, + "distance": 1669.61, + "gen_feat_1": 506.91, + "gen_feat_2": 0.486343, + "gen_feat_3": 513.29 + } + }, + { + "id": "t_movie_gen_60", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 137.16, + "distance": 1727.65, + "gen_feat_1": 511.78, + "gen_feat_2": 0.498191, + "gen_feat_3": 495.09 + } + }, + { + "id": "t_movie_gen_61", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.06, + "time": 131.51, + "distance": 1688.72, + "gen_feat_1": 501.65, + "gen_feat_2": 0.503774, + "gen_feat_3": 494.98 + } + }, + { + "id": "t_movie_gen_62", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 134.94, + "distance": 1688.34, + "gen_feat_1": 486.17, + "gen_feat_2": 0.506252, + "gen_feat_3": 499.8 + } + }, + { + "id": "t_movie_gen_63", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.0, + "time": 132.52, + "distance": 1696.65, + "gen_feat_1": 514.69, + "gen_feat_2": 0.493209, + "gen_feat_3": 485.24 + } + }, + { + "id": "t_movie_gen_64", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.73, + "time": 131.33, + "distance": 1699.32, + "gen_feat_1": 494.73, + "gen_feat_2": 0.500638, + "gen_feat_3": 507.36 + } + }, + { + "id": "t_movie_gen_65", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.28, + "time": 135.57, + "distance": 1672.37, + "gen_feat_1": 512.61, + "gen_feat_2": 0.49003, + "gen_feat_3": 498.67 + } + }, + { + "id": "t_movie_gen_66", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.81, + "time": 133.8, + "distance": 1700.55, + "gen_feat_1": 512.0, + "gen_feat_2": 0.486179, + "gen_feat_3": 501.33 + } + }, + { + "id": "t_movie_gen_67", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.03, + "time": 131.77, + "distance": 1745.74, + "gen_feat_1": 503.3, + "gen_feat_2": 0.51441, + "gen_feat_3": 486.9 + } + }, + { + "id": "t_movie_gen_68", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.9, + "time": 137.31, + "distance": 1655.07, + "gen_feat_1": 485.6, + "gen_feat_2": 0.49856, + "gen_feat_3": 495.04 + } + }, + { + "id": "t_movie_gen_69", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.19, + "time": 137.9, + "distance": 1713.23, + "gen_feat_1": 510.23, + "gen_feat_2": 0.490473, + "gen_feat_3": 492.48 + } + }, + { + "id": "t_movie_gen_70", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.92, + "time": 137.74, + "distance": 1742.03, + "gen_feat_1": 497.94, + "gen_feat_2": 0.514756, + "gen_feat_3": 487.31 + } + }, + { + "id": "t_movie_gen_71", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.28, + "time": 134.06, + "distance": 1654.96, + "gen_feat_1": 510.56, + "gen_feat_2": 0.492021, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_movie_gen_72", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 135.82, + "distance": 1738.49, + "gen_feat_1": 500.42, + "gen_feat_2": 0.493135, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_73", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 134.69, + "distance": 1663.19, + "gen_feat_1": 491.2, + "gen_feat_2": 0.505794, + "gen_feat_3": 504.69 + } + }, + { + "id": "t_movie_gen_74", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.82, + "time": 132.56, + "distance": 1679.26, + "gen_feat_1": 497.39, + "gen_feat_2": 0.485217, + "gen_feat_3": 513.12 + } + }, + { + "id": "t_movie_gen_75", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.18, + "time": 134.95, + "distance": 1745.08, + "gen_feat_1": 491.08, + "gen_feat_2": 0.495277, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_movie_gen_76", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.16, + "time": 138.62, + "distance": 1666.98, + "gen_feat_1": 501.07, + "gen_feat_2": 0.506814, + "gen_feat_3": 489.44 + } + }, + { + "id": "t_movie_gen_77", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.76, + "time": 130.95, + "distance": 1675.39, + "gen_feat_1": 513.23, + "gen_feat_2": 0.496512, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_movie_gen_78", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.99, + "time": 132.12, + "distance": 1674.54, + "gen_feat_1": 495.99, + "gen_feat_2": 0.496439, + "gen_feat_3": 506.49 + } + }, + { + "id": "t_movie_gen_79", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.84, + "time": 132.9, + "distance": 1698.58, + "gen_feat_1": 486.83, + "gen_feat_2": 0.487385, + "gen_feat_3": 489.3 + } + }, + { + "id": "t_movie_gen_80", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 135.25, + "distance": 1703.48, + "gen_feat_1": 497.71, + "gen_feat_2": 0.506091, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_movie_gen_81", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.08, + "time": 138.34, + "distance": 1706.78, + "gen_feat_1": 501.18, + "gen_feat_2": 0.503416, + "gen_feat_3": 493.11 + } + }, + { + "id": "t_movie_gen_82", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.95, + "time": 132.28, + "distance": 1658.35, + "gen_feat_1": 488.13, + "gen_feat_2": 0.514958, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_83", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 135.04, + "distance": 1663.79, + "gen_feat_1": 495.07, + "gen_feat_2": 0.489223, + "gen_feat_3": 514.52 + } + }, + { + "id": "t_movie_gen_84", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.76, + "time": 137.41, + "distance": 1703.65, + "gen_feat_1": 504.9, + "gen_feat_2": 0.503529, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_movie_gen_85", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.08, + "time": 135.55, + "distance": 1691.79, + "gen_feat_1": 503.38, + "gen_feat_2": 0.5004, + "gen_feat_3": 510.63 + } + }, + { + "id": "t_movie_gen_86", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.24, + "time": 133.11, + "distance": 1689.53, + "gen_feat_1": 509.79, + "gen_feat_2": 0.49881, + "gen_feat_3": 488.86 + } + }, + { + "id": "t_movie_gen_87", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.89, + "time": 137.15, + "distance": 1698.06, + "gen_feat_1": 503.82, + "gen_feat_2": 0.50464, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_88", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.13, + "time": 131.18, + "distance": 1660.59, + "gen_feat_1": 492.85, + "gen_feat_2": 0.514114, + "gen_feat_3": 513.82 + } + }, + { + "id": "t_movie_gen_89", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.87, + "time": 135.02, + "distance": 1741.57, + "gen_feat_1": 501.92, + "gen_feat_2": 0.508398, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_90", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.28, + "time": 137.35, + "distance": 1718.09, + "gen_feat_1": 488.68, + "gen_feat_2": 0.49537, + "gen_feat_3": 493.95 + } + }, + { + "id": "t_movie_gen_91", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 137.3, + "distance": 1693.34, + "gen_feat_1": 493.19, + "gen_feat_2": 0.495672, + "gen_feat_3": 488.25 + } + }, + { + "id": "t_movie_gen_92", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.83, + "time": 137.58, + "distance": 1744.3, + "gen_feat_1": 491.56, + "gen_feat_2": 0.498387, + "gen_feat_3": 511.69 + } + }, + { + "id": "t_movie_gen_93", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.91, + "time": 133.34, + "distance": 1702.93, + "gen_feat_1": 488.01, + "gen_feat_2": 0.502779, + "gen_feat_3": 491.18 + } + }, + { + "id": "t_movie_gen_94", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 134.1, + "distance": 1680.7, + "gen_feat_1": 497.7, + "gen_feat_2": 0.497436, + "gen_feat_3": 502.47 + } + }, + { + "id": "t_movie_gen_95", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 136.67, + "distance": 1705.0, + "gen_feat_1": 488.28, + "gen_feat_2": 0.487878, + "gen_feat_3": 495.8 + } + }, + { + "id": "t_movie_gen_96", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.9, + "time": 134.07, + "distance": 1659.49, + "gen_feat_1": 492.47, + "gen_feat_2": 0.492451, + "gen_feat_3": 511.78 + } + }, + { + "id": "t_movie_gen_97", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.21, + "time": 134.31, + "distance": 1734.61, + "gen_feat_1": 493.2, + "gen_feat_2": 0.488477, + "gen_feat_3": 503.93 + } + }, + { + "id": "t_movie_gen_98", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 135.67, + "distance": 1729.26, + "gen_feat_1": 489.64, + "gen_feat_2": 0.491387, + "gen_feat_3": 506.86 + } + }, + { + "id": "t_movie_gen_99", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.79, + "time": 133.64, + "distance": 1673.71, + "gen_feat_1": 505.04, + "gen_feat_2": 0.505422, + "gen_feat_3": 513.37 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_dining", + "kind": "TASK", + "task_id": "t_dining" + }, + { + "id": "n_shopping", + "kind": "TASK", + "task_id": "t_shopping" + }, + { + "id": "n_movie", + "kind": "TASK", + "task_id": "t_movie" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "time": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "distance": { + "neutral": 0, + "compose": { + "seq": { + "fn": "MAX" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "c_within_2km", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "distance", + "op": "<=", + "value": 2000, + "hard": false + }, + { + "id": "c_time_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "time", + "op": "<=", + "value": 240, + "hard": false + }, + { + "id": "c_cost_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 100, + "hard": false + }, + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 50.07, + "hard": false + }, + { + "id": "gen_c_local_t_dining_time_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_dining" + ], + "attribute_id": "time", + "op": "<=", + "value": 59.79, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_dining", + "t_shopping" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_dining", + "t_movie" + ], + "hard": false + } + ], + "objective": { + "type": "MONO", + "targets": [ + "cost" + ], + "weights": { + "cost": 1.0 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/zhang2014-entertainment-planner-running-example_mono_utility_hard.json b/experimentation/instances/zhang2014-entertainment-planner-running-example_mono_utility_hard.json new file mode 100644 index 0000000..2681adc --- /dev/null +++ b/experimentation/instances/zhang2014-entertainment-planner-running-example_mono_utility_hard.json @@ -0,0 +1,4540 @@ +{ + "metadata": { + "id": "zhang2014-entertainment-planner-running-example_mono_utility_hard", + "name": "Personal Entertainment Planner (Zhang et al. 2014) [mono_utility, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:05Z", + "description": "Modeled from the motivating example in 'Context-aware Generic Service Discovery and Service Composition' (IEEE MobServ 2014).", + "paper": { + "title": "Context-aware Generic Service Discovery and Service Composition", + "authors": "Y. Zhang et al.", + "year": 2014, + "doi": "10.1109/MobServ.2014.27" + } + }, + "features": [ + { + "id": "cost", + "name": "Total money cost (USD)", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "time", + "name": "Total time cost (minutes)", + "direction": "MINIMIZE", + "unit": "min", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1440 + } + }, + { + "id": "distance", + "name": "Distance from user's current location (meters)", + "direction": "MINIMIZE", + "unit": "m", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 50000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_rest_autre_saison", + "name": "Restaurant L’Autre Saison" + }, + { + "id": "p_cinema_banque_scotia", + "name": "Cinema Banque Scotia Montreal" + }, + { + "id": "p_seven_night_club", + "name": "Seven Night Club" + }, + { + "id": "p_local_shopping", + "name": "Local Shopping (nearby venue)" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_dining", + "name": "Restaurant / Dining activity" + }, + { + "id": "t_shopping", + "name": "Shopping activity" + }, + { + "id": "t_movie", + "name": "Movie activity" + } + ], + "candidates": [ + { + "id": "c_dining_autre_saison", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison", + "features": { + "cost": 20, + "time": 60, + "distance": 1600, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_dining_seven_night_club", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Seven Night Club", + "features": { + "cost": 20, + "time": 60, + "distance": 1800, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopping_local", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue", + "features": { + "cost": 20, + "time": 45, + "distance": 1200, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_movie_the_help_banque_scotia", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal", + "features": { + "cost": 10, + "time": 135, + "distance": 1700, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_dining_gen_1", + "task_id": "t_dining", + "provider_id": "p_gen_shared", + "name": "Dinner at Restaurant L’Autre Saison (Gen Shared)", + "features": { + "cost": 20.2, + "time": 59.79, + "distance": 1570.05, + "gen_feat_1": 508.24, + "gen_feat_2": 0.514901, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_shopping_gen_1", + "task_id": "t_shopping", + "provider_id": "p_gen_shared", + "name": "Shopping at a nearby venue (Gen Shared)", + "features": { + "cost": 19.87, + "time": 44.98, + "distance": 1189.95, + "gen_feat_1": 485.24, + "gen_feat_2": 0.486287, + "gen_feat_3": 500.42 + } + }, + { + "id": "t_movie_gen_1", + "task_id": "t_movie", + "provider_id": "p_gen_shared", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen Shared)", + "features": { + "cost": 9.82, + "time": 134.28, + "distance": 1742.9, + "gen_feat_1": 512.03, + "gen_feat_2": 0.505972, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_dining_gen_2", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.53, + "time": 59.13, + "distance": 1559.02, + "gen_feat_1": 498.66, + "gen_feat_2": 0.488957, + "gen_feat_3": 503.61 + } + }, + { + "id": "t_dining_gen_3", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.94, + "time": 58.5, + "distance": 1591.09, + "gen_feat_1": 495.96, + "gen_feat_2": 0.504969, + "gen_feat_3": 506.77 + } + }, + { + "id": "t_dining_gen_4", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.8, + "time": 61.46, + "distance": 1629.91, + "gen_feat_1": 510.53, + "gen_feat_2": 0.508, + "gen_feat_3": 491.98 + } + }, + { + "id": "t_dining_gen_5", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.22, + "time": 60.39, + "distance": 1564.48, + "gen_feat_1": 491.41, + "gen_feat_2": 0.490673, + "gen_feat_3": 490.61 + } + }, + { + "id": "t_dining_gen_6", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.38, + "time": 58.67, + "distance": 1626.15, + "gen_feat_1": 488.5, + "gen_feat_2": 0.49348, + "gen_feat_3": 495.75 + } + }, + { + "id": "t_dining_gen_7", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.18, + "time": 60.72, + "distance": 1555.22, + "gen_feat_1": 505.8, + "gen_feat_2": 0.506719, + "gen_feat_3": 499.33 + } + }, + { + "id": "t_dining_gen_8", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.43, + "time": 59.64, + "distance": 1598.13, + "gen_feat_1": 503.89, + "gen_feat_2": 0.506945, + "gen_feat_3": 508.17 + } + }, + { + "id": "t_dining_gen_9", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.64, + "time": 60.54, + "distance": 1604.33, + "gen_feat_1": 486.84, + "gen_feat_2": 0.506628, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_dining_gen_10", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 60.17, + "distance": 1616.85, + "gen_feat_1": 507.44, + "gen_feat_2": 0.489997, + "gen_feat_3": 502.16 + } + }, + { + "id": "t_dining_gen_11", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.68, + "time": 59.16, + "distance": 1620.42, + "gen_feat_1": 507.98, + "gen_feat_2": 0.488942, + "gen_feat_3": 489.19 + } + }, + { + "id": "t_dining_gen_12", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.74, + "time": 59.04, + "distance": 1602.16, + "gen_feat_1": 504.58, + "gen_feat_2": 0.489389, + "gen_feat_3": 507.41 + } + }, + { + "id": "t_dining_gen_13", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.47, + "time": 58.89, + "distance": 1622.97, + "gen_feat_1": 492.31, + "gen_feat_2": 0.503154, + "gen_feat_3": 508.55 + } + }, + { + "id": "t_dining_gen_14", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.72, + "time": 58.91, + "distance": 1626.35, + "gen_feat_1": 509.41, + "gen_feat_2": 0.490291, + "gen_feat_3": 514.74 + } + }, + { + "id": "t_dining_gen_15", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.59, + "time": 60.67, + "distance": 1631.73, + "gen_feat_1": 493.43, + "gen_feat_2": 0.498961, + "gen_feat_3": 492.15 + } + }, + { + "id": "t_dining_gen_16", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.21, + "time": 59.57, + "distance": 1621.68, + "gen_feat_1": 502.04, + "gen_feat_2": 0.491944, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_dining_gen_17", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.33, + "time": 59.99, + "distance": 1602.82, + "gen_feat_1": 513.49, + "gen_feat_2": 0.510425, + "gen_feat_3": 506.46 + } + }, + { + "id": "t_dining_gen_18", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.02, + "time": 60.13, + "distance": 1639.2, + "gen_feat_1": 498.4, + "gen_feat_2": 0.499582, + "gen_feat_3": 504.62 + } + }, + { + "id": "t_dining_gen_19", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.03, + "time": 60.73, + "distance": 1642.13, + "gen_feat_1": 507.63, + "gen_feat_2": 0.500514, + "gen_feat_3": 495.73 + } + }, + { + "id": "t_dining_gen_20", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.33, + "time": 59.96, + "distance": 1568.96, + "gen_feat_1": 488.36, + "gen_feat_2": 0.514752, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_dining_gen_21", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.8, + "time": 58.42, + "distance": 1555.46, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486429, + "gen_feat_3": 488.41 + } + }, + { + "id": "t_dining_gen_22", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.66, + "time": 61.62, + "distance": 1580.67, + "gen_feat_1": 491.06, + "gen_feat_2": 0.506184, + "gen_feat_3": 501.23 + } + }, + { + "id": "t_dining_gen_23", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.42, + "time": 61.78, + "distance": 1622.72, + "gen_feat_1": 490.83, + "gen_feat_2": 0.489949, + "gen_feat_3": 487.73 + } + }, + { + "id": "t_dining_gen_24", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.71, + "time": 59.51, + "distance": 1580.85, + "gen_feat_1": 501.15, + "gen_feat_2": 0.50297, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_25", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.42, + "time": 61.41, + "distance": 1578.66, + "gen_feat_1": 507.39, + "gen_feat_2": 0.499268, + "gen_feat_3": 490.28 + } + }, + { + "id": "t_dining_gen_26", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.55, + "time": 58.26, + "distance": 1560.85, + "gen_feat_1": 492.17, + "gen_feat_2": 0.492399, + "gen_feat_3": 511.94 + } + }, + { + "id": "t_dining_gen_27", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.48, + "time": 58.34, + "distance": 1631.2, + "gen_feat_1": 498.39, + "gen_feat_2": 0.490821, + "gen_feat_3": 491.03 + } + }, + { + "id": "t_dining_gen_28", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.04, + "time": 61.28, + "distance": 1606.8, + "gen_feat_1": 512.73, + "gen_feat_2": 0.509267, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_dining_gen_29", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.76, + "time": 60.3, + "distance": 1569.61, + "gen_feat_1": 490.22, + "gen_feat_2": 0.496831, + "gen_feat_3": 496.53 + } + }, + { + "id": "t_dining_gen_30", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.71, + "time": 60.3, + "distance": 1623.3, + "gen_feat_1": 500.21, + "gen_feat_2": 0.496569, + "gen_feat_3": 498.99 + } + }, + { + "id": "t_dining_gen_31", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.86, + "time": 59.05, + "distance": 1588.58, + "gen_feat_1": 485.96, + "gen_feat_2": 0.512749, + "gen_feat_3": 498.55 + } + }, + { + "id": "t_dining_gen_32", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.8, + "time": 59.8, + "distance": 1560.3, + "gen_feat_1": 512.24, + "gen_feat_2": 0.486102, + "gen_feat_3": 508.8 + } + }, + { + "id": "t_dining_gen_33", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.49, + "time": 61.12, + "distance": 1612.82, + "gen_feat_1": 506.05, + "gen_feat_2": 0.504153, + "gen_feat_3": 510.28 + } + }, + { + "id": "t_dining_gen_34", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.66, + "time": 58.74, + "distance": 1627.51, + "gen_feat_1": 494.47, + "gen_feat_2": 0.509322, + "gen_feat_3": 485.53 + } + }, + { + "id": "t_dining_gen_35", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.14, + "time": 60.57, + "distance": 1626.08, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513739, + "gen_feat_3": 510.69 + } + }, + { + "id": "t_dining_gen_36", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.57, + "time": 58.38, + "distance": 1610.88, + "gen_feat_1": 495.23, + "gen_feat_2": 0.509726, + "gen_feat_3": 512.08 + } + }, + { + "id": "t_dining_gen_37", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.41, + "distance": 1575.46, + "gen_feat_1": 512.15, + "gen_feat_2": 0.492042, + "gen_feat_3": 505.13 + } + }, + { + "id": "t_dining_gen_38", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.22, + "time": 59.29, + "distance": 1557.64, + "gen_feat_1": 489.83, + "gen_feat_2": 0.49146, + "gen_feat_3": 495.3 + } + }, + { + "id": "t_dining_gen_39", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.59, + "time": 61.53, + "distance": 1562.65, + "gen_feat_1": 495.8, + "gen_feat_2": 0.496923, + "gen_feat_3": 507.91 + } + }, + { + "id": "t_dining_gen_40", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.43, + "time": 60.01, + "distance": 1604.0, + "gen_feat_1": 500.49, + "gen_feat_2": 0.514685, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_41", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.58, + "time": 60.72, + "distance": 1645.52, + "gen_feat_1": 487.19, + "gen_feat_2": 0.508959, + "gen_feat_3": 497.39 + } + }, + { + "id": "t_dining_gen_42", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.2, + "time": 59.26, + "distance": 1581.92, + "gen_feat_1": 509.7, + "gen_feat_2": 0.513201, + "gen_feat_3": 491.13 + } + }, + { + "id": "t_dining_gen_43", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.45, + "time": 60.26, + "distance": 1568.18, + "gen_feat_1": 493.86, + "gen_feat_2": 0.514555, + "gen_feat_3": 489.48 + } + }, + { + "id": "t_dining_gen_44", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.58, + "time": 58.5, + "distance": 1617.8, + "gen_feat_1": 491.08, + "gen_feat_2": 0.513671, + "gen_feat_3": 486.88 + } + }, + { + "id": "t_dining_gen_45", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.68, + "time": 61.23, + "distance": 1579.97, + "gen_feat_1": 509.82, + "gen_feat_2": 0.504088, + "gen_feat_3": 512.95 + } + }, + { + "id": "t_dining_gen_46", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 60.56, + "distance": 1641.45, + "gen_feat_1": 499.89, + "gen_feat_2": 0.510488, + "gen_feat_3": 491.3 + } + }, + { + "id": "t_dining_gen_47", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.94, + "time": 58.84, + "distance": 1629.37, + "gen_feat_1": 494.2, + "gen_feat_2": 0.49711, + "gen_feat_3": 496.8 + } + }, + { + "id": "t_dining_gen_48", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.23, + "time": 58.97, + "distance": 1607.14, + "gen_feat_1": 485.39, + "gen_feat_2": 0.485086, + "gen_feat_3": 504.57 + } + }, + { + "id": "t_dining_gen_49", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.47, + "time": 59.57, + "distance": 1615.57, + "gen_feat_1": 495.03, + "gen_feat_2": 0.503496, + "gen_feat_3": 509.51 + } + }, + { + "id": "t_dining_gen_50", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.7, + "distance": 1583.69, + "gen_feat_1": 489.31, + "gen_feat_2": 0.498993, + "gen_feat_3": 498.25 + } + }, + { + "id": "t_dining_gen_51", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.06, + "time": 60.11, + "distance": 1630.7, + "gen_feat_1": 507.83, + "gen_feat_2": 0.497927, + "gen_feat_3": 485.62 + } + }, + { + "id": "t_dining_gen_52", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.53, + "time": 58.59, + "distance": 1646.13, + "gen_feat_1": 489.54, + "gen_feat_2": 0.503777, + "gen_feat_3": 487.65 + } + }, + { + "id": "t_dining_gen_53", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.9, + "time": 58.5, + "distance": 1634.44, + "gen_feat_1": 514.43, + "gen_feat_2": 0.508093, + "gen_feat_3": 499.44 + } + }, + { + "id": "t_dining_gen_54", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.18, + "time": 58.68, + "distance": 1576.83, + "gen_feat_1": 491.93, + "gen_feat_2": 0.485409, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_dining_gen_55", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.0, + "distance": 1581.79, + "gen_feat_1": 489.92, + "gen_feat_2": 0.49016, + "gen_feat_3": 513.4 + } + }, + { + "id": "t_dining_gen_56", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.18, + "time": 61.73, + "distance": 1637.68, + "gen_feat_1": 492.48, + "gen_feat_2": 0.497966, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_dining_gen_57", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.2, + "time": 61.78, + "distance": 1646.08, + "gen_feat_1": 508.92, + "gen_feat_2": 0.500426, + "gen_feat_3": 499.7 + } + }, + { + "id": "t_dining_gen_58", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.57, + "time": 59.32, + "distance": 1580.58, + "gen_feat_1": 509.74, + "gen_feat_2": 0.510379, + "gen_feat_3": 512.86 + } + }, + { + "id": "t_dining_gen_59", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.54, + "time": 59.3, + "distance": 1570.05, + "gen_feat_1": 486.4, + "gen_feat_2": 0.503502, + "gen_feat_3": 498.65 + } + }, + { + "id": "t_dining_gen_60", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.18, + "time": 61.43, + "distance": 1636.11, + "gen_feat_1": 485.66, + "gen_feat_2": 0.498532, + "gen_feat_3": 506.32 + } + }, + { + "id": "t_dining_gen_61", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.01, + "time": 59.61, + "distance": 1626.73, + "gen_feat_1": 507.2, + "gen_feat_2": 0.505098, + "gen_feat_3": 499.85 + } + }, + { + "id": "t_dining_gen_62", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.22, + "time": 59.78, + "distance": 1646.36, + "gen_feat_1": 500.64, + "gen_feat_2": 0.500049, + "gen_feat_3": 504.88 + } + }, + { + "id": "t_dining_gen_63", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.11, + "time": 59.7, + "distance": 1621.52, + "gen_feat_1": 494.18, + "gen_feat_2": 0.498313, + "gen_feat_3": 506.17 + } + }, + { + "id": "t_dining_gen_64", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.71, + "time": 61.36, + "distance": 1568.12, + "gen_feat_1": 493.75, + "gen_feat_2": 0.505406, + "gen_feat_3": 512.82 + } + }, + { + "id": "t_dining_gen_65", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.4, + "time": 58.28, + "distance": 1604.89, + "gen_feat_1": 487.06, + "gen_feat_2": 0.502445, + "gen_feat_3": 511.12 + } + }, + { + "id": "t_dining_gen_66", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 59.57, + "distance": 1581.66, + "gen_feat_1": 513.25, + "gen_feat_2": 0.493068, + "gen_feat_3": 505.54 + } + }, + { + "id": "t_dining_gen_67", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.21, + "time": 60.81, + "distance": 1606.42, + "gen_feat_1": 493.36, + "gen_feat_2": 0.50459, + "gen_feat_3": 493.01 + } + }, + { + "id": "t_dining_gen_68", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 59.09, + "distance": 1611.43, + "gen_feat_1": 505.83, + "gen_feat_2": 0.502644, + "gen_feat_3": 504.4 + } + }, + { + "id": "t_dining_gen_69", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.92, + "time": 61.04, + "distance": 1579.9, + "gen_feat_1": 512.7, + "gen_feat_2": 0.488813, + "gen_feat_3": 500.85 + } + }, + { + "id": "t_dining_gen_70", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.74, + "time": 59.83, + "distance": 1615.86, + "gen_feat_1": 505.67, + "gen_feat_2": 0.48967, + "gen_feat_3": 503.59 + } + }, + { + "id": "t_dining_gen_71", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 61.74, + "distance": 1585.25, + "gen_feat_1": 495.74, + "gen_feat_2": 0.490106, + "gen_feat_3": 499.93 + } + }, + { + "id": "t_dining_gen_72", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.9, + "time": 58.61, + "distance": 1604.96, + "gen_feat_1": 509.49, + "gen_feat_2": 0.512456, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_73", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.41, + "time": 59.23, + "distance": 1631.69, + "gen_feat_1": 507.39, + "gen_feat_2": 0.504155, + "gen_feat_3": 514.37 + } + }, + { + "id": "t_dining_gen_74", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.5, + "time": 58.7, + "distance": 1628.56, + "gen_feat_1": 514.96, + "gen_feat_2": 0.498875, + "gen_feat_3": 512.16 + } + }, + { + "id": "t_dining_gen_75", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.83, + "time": 61.78, + "distance": 1589.19, + "gen_feat_1": 501.13, + "gen_feat_2": 0.504679, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_dining_gen_76", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.02, + "time": 61.78, + "distance": 1596.36, + "gen_feat_1": 511.57, + "gen_feat_2": 0.51185, + "gen_feat_3": 493.99 + } + }, + { + "id": "t_dining_gen_77", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.38, + "time": 59.52, + "distance": 1573.49, + "gen_feat_1": 513.61, + "gen_feat_2": 0.50886, + "gen_feat_3": 505.08 + } + }, + { + "id": "t_dining_gen_78", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.28, + "time": 59.03, + "distance": 1628.26, + "gen_feat_1": 513.77, + "gen_feat_2": 0.508209, + "gen_feat_3": 504.63 + } + }, + { + "id": "t_dining_gen_79", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.75, + "time": 60.98, + "distance": 1603.39, + "gen_feat_1": 510.74, + "gen_feat_2": 0.51442, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_dining_gen_80", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.34, + "time": 59.39, + "distance": 1607.15, + "gen_feat_1": 489.01, + "gen_feat_2": 0.508841, + "gen_feat_3": 503.65 + } + }, + { + "id": "t_dining_gen_81", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.78, + "time": 61.32, + "distance": 1606.79, + "gen_feat_1": 494.77, + "gen_feat_2": 0.498081, + "gen_feat_3": 490.68 + } + }, + { + "id": "t_dining_gen_82", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.0, + "time": 60.47, + "distance": 1578.03, + "gen_feat_1": 505.85, + "gen_feat_2": 0.496498, + "gen_feat_3": 494.3 + } + }, + { + "id": "t_dining_gen_83", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.59, + "time": 60.4, + "distance": 1576.41, + "gen_feat_1": 487.54, + "gen_feat_2": 0.490813, + "gen_feat_3": 506.97 + } + }, + { + "id": "t_dining_gen_84", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.45, + "time": 58.59, + "distance": 1635.41, + "gen_feat_1": 507.53, + "gen_feat_2": 0.499359, + "gen_feat_3": 511.49 + } + }, + { + "id": "t_dining_gen_85", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.55, + "time": 59.37, + "distance": 1578.95, + "gen_feat_1": 500.14, + "gen_feat_2": 0.504331, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_dining_gen_86", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.11, + "distance": 1556.1, + "gen_feat_1": 513.36, + "gen_feat_2": 0.512958, + "gen_feat_3": 493.44 + } + }, + { + "id": "t_dining_gen_87", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.26, + "time": 59.23, + "distance": 1563.62, + "gen_feat_1": 489.36, + "gen_feat_2": 0.51222, + "gen_feat_3": 503.86 + } + }, + { + "id": "t_dining_gen_88", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.46, + "time": 61.2, + "distance": 1588.14, + "gen_feat_1": 488.89, + "gen_feat_2": 0.496175, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_dining_gen_89", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.79, + "time": 58.63, + "distance": 1622.85, + "gen_feat_1": 512.62, + "gen_feat_2": 0.485995, + "gen_feat_3": 487.83 + } + }, + { + "id": "t_dining_gen_90", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.48, + "time": 58.69, + "distance": 1640.49, + "gen_feat_1": 511.37, + "gen_feat_2": 0.494218, + "gen_feat_3": 505.83 + } + }, + { + "id": "t_dining_gen_91", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.58, + "time": 58.72, + "distance": 1630.9, + "gen_feat_1": 505.33, + "gen_feat_2": 0.485446, + "gen_feat_3": 496.64 + } + }, + { + "id": "t_dining_gen_92", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.04, + "time": 59.56, + "distance": 1559.07, + "gen_feat_1": 491.21, + "gen_feat_2": 0.509726, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_93", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.84, + "time": 60.45, + "distance": 1596.68, + "gen_feat_1": 493.98, + "gen_feat_2": 0.489239, + "gen_feat_3": 493.56 + } + }, + { + "id": "t_dining_gen_94", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.56, + "time": 59.95, + "distance": 1630.28, + "gen_feat_1": 488.49, + "gen_feat_2": 0.505218, + "gen_feat_3": 491.42 + } + }, + { + "id": "t_dining_gen_95", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.97, + "time": 59.51, + "distance": 1593.3, + "gen_feat_1": 488.66, + "gen_feat_2": 0.490214, + "gen_feat_3": 504.25 + } + }, + { + "id": "t_dining_gen_96", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.85, + "time": 58.35, + "distance": 1552.26, + "gen_feat_1": 503.49, + "gen_feat_2": 0.48523, + "gen_feat_3": 504.39 + } + }, + { + "id": "t_dining_gen_97", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.51, + "time": 59.5, + "distance": 1634.44, + "gen_feat_1": 497.31, + "gen_feat_2": 0.5107, + "gen_feat_3": 507.86 + } + }, + { + "id": "t_dining_gen_98", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.5, + "time": 61.17, + "distance": 1593.89, + "gen_feat_1": 510.31, + "gen_feat_2": 0.50078, + "gen_feat_3": 494.95 + } + }, + { + "id": "t_shopping_gen_2", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.95, + "time": 44.3, + "distance": 1198.71, + "gen_feat_1": 508.4, + "gen_feat_2": 0.485625, + "gen_feat_3": 507.99 + } + }, + { + "id": "t_shopping_gen_3", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 44.18, + "distance": 1196.21, + "gen_feat_1": 485.72, + "gen_feat_2": 0.488455, + "gen_feat_3": 489.7 + } + }, + { + "id": "t_shopping_gen_4", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.78, + "time": 44.9, + "distance": 1179.12, + "gen_feat_1": 503.26, + "gen_feat_2": 0.498291, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_shopping_gen_5", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.51, + "time": 44.53, + "distance": 1216.23, + "gen_feat_1": 510.8, + "gen_feat_2": 0.507066, + "gen_feat_3": 504.03 + } + }, + { + "id": "t_shopping_gen_6", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.18, + "time": 44.06, + "distance": 1199.34, + "gen_feat_1": 501.17, + "gen_feat_2": 0.493458, + "gen_feat_3": 510.83 + } + }, + { + "id": "t_shopping_gen_7", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.59, + "time": 45.0, + "distance": 1183.14, + "gen_feat_1": 501.56, + "gen_feat_2": 0.496232, + "gen_feat_3": 496.33 + } + }, + { + "id": "t_shopping_gen_8", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.45, + "time": 43.75, + "distance": 1196.19, + "gen_feat_1": 488.54, + "gen_feat_2": 0.508864, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_9", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.29, + "time": 45.49, + "distance": 1235.6, + "gen_feat_1": 505.19, + "gen_feat_2": 0.486447, + "gen_feat_3": 505.3 + } + }, + { + "id": "t_shopping_gen_10", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.2, + "time": 44.86, + "distance": 1227.31, + "gen_feat_1": 487.19, + "gen_feat_2": 0.512416, + "gen_feat_3": 499.73 + } + }, + { + "id": "t_shopping_gen_11", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.86, + "time": 44.51, + "distance": 1227.77, + "gen_feat_1": 488.24, + "gen_feat_2": 0.510589, + "gen_feat_3": 510.74 + } + }, + { + "id": "t_shopping_gen_12", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.87, + "time": 44.69, + "distance": 1170.61, + "gen_feat_1": 503.79, + "gen_feat_2": 0.487994, + "gen_feat_3": 485.28 + } + }, + { + "id": "t_shopping_gen_13", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.87, + "time": 46.21, + "distance": 1228.85, + "gen_feat_1": 488.6, + "gen_feat_2": 0.499239, + "gen_feat_3": 503.2 + } + }, + { + "id": "t_shopping_gen_14", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.47, + "time": 44.09, + "distance": 1191.47, + "gen_feat_1": 510.69, + "gen_feat_2": 0.500607, + "gen_feat_3": 501.94 + } + }, + { + "id": "t_shopping_gen_15", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.91, + "time": 44.79, + "distance": 1194.44, + "gen_feat_1": 493.04, + "gen_feat_2": 0.493381, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_16", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.74, + "time": 45.76, + "distance": 1214.32, + "gen_feat_1": 508.04, + "gen_feat_2": 0.505849, + "gen_feat_3": 514.42 + } + }, + { + "id": "t_shopping_gen_17", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.56, + "time": 44.53, + "distance": 1186.46, + "gen_feat_1": 497.1, + "gen_feat_2": 0.507483, + "gen_feat_3": 487.33 + } + }, + { + "id": "t_shopping_gen_18", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.3, + "time": 46.02, + "distance": 1191.93, + "gen_feat_1": 502.5, + "gen_feat_2": 0.489832, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_shopping_gen_19", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.29, + "time": 44.76, + "distance": 1178.65, + "gen_feat_1": 486.31, + "gen_feat_2": 0.501927, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_shopping_gen_20", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.59, + "time": 45.62, + "distance": 1234.59, + "gen_feat_1": 508.23, + "gen_feat_2": 0.488622, + "gen_feat_3": 505.15 + } + }, + { + "id": "t_shopping_gen_21", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.41, + "time": 44.06, + "distance": 1185.1, + "gen_feat_1": 498.37, + "gen_feat_2": 0.491076, + "gen_feat_3": 502.07 + } + }, + { + "id": "t_shopping_gen_22", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.07, + "time": 45.23, + "distance": 1172.35, + "gen_feat_1": 489.15, + "gen_feat_2": 0.487341, + "gen_feat_3": 502.22 + } + }, + { + "id": "t_shopping_gen_23", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.07, + "time": 44.11, + "distance": 1228.63, + "gen_feat_1": 489.68, + "gen_feat_2": 0.497214, + "gen_feat_3": 510.3 + } + }, + { + "id": "t_shopping_gen_24", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.79, + "time": 45.29, + "distance": 1211.47, + "gen_feat_1": 513.99, + "gen_feat_2": 0.511272, + "gen_feat_3": 512.18 + } + }, + { + "id": "t_shopping_gen_25", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.49, + "time": 45.68, + "distance": 1197.16, + "gen_feat_1": 504.19, + "gen_feat_2": 0.507954, + "gen_feat_3": 509.7 + } + }, + { + "id": "t_shopping_gen_26", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.61, + "time": 45.73, + "distance": 1191.91, + "gen_feat_1": 499.13, + "gen_feat_2": 0.502797, + "gen_feat_3": 486.18 + } + }, + { + "id": "t_shopping_gen_27", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.64, + "time": 45.28, + "distance": 1176.71, + "gen_feat_1": 505.64, + "gen_feat_2": 0.491227, + "gen_feat_3": 508.35 + } + }, + { + "id": "t_shopping_gen_28", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.87, + "time": 45.0, + "distance": 1216.17, + "gen_feat_1": 500.61, + "gen_feat_2": 0.512609, + "gen_feat_3": 509.87 + } + }, + { + "id": "t_shopping_gen_29", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.37, + "time": 44.26, + "distance": 1180.24, + "gen_feat_1": 487.72, + "gen_feat_2": 0.485295, + "gen_feat_3": 487.2 + } + }, + { + "id": "t_shopping_gen_30", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.65, + "time": 44.57, + "distance": 1197.12, + "gen_feat_1": 500.2, + "gen_feat_2": 0.506494, + "gen_feat_3": 511.02 + } + }, + { + "id": "t_shopping_gen_31", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.54, + "time": 43.79, + "distance": 1190.28, + "gen_feat_1": 501.09, + "gen_feat_2": 0.496883, + "gen_feat_3": 504.0 + } + }, + { + "id": "t_shopping_gen_32", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.4, + "time": 44.15, + "distance": 1210.36, + "gen_feat_1": 506.65, + "gen_feat_2": 0.494619, + "gen_feat_3": 489.54 + } + }, + { + "id": "t_shopping_gen_33", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.78, + "time": 44.05, + "distance": 1224.7, + "gen_feat_1": 505.11, + "gen_feat_2": 0.497586, + "gen_feat_3": 502.56 + } + }, + { + "id": "t_shopping_gen_34", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.93, + "time": 45.15, + "distance": 1219.85, + "gen_feat_1": 498.34, + "gen_feat_2": 0.488983, + "gen_feat_3": 494.13 + } + }, + { + "id": "t_shopping_gen_35", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.82, + "time": 44.55, + "distance": 1224.73, + "gen_feat_1": 511.51, + "gen_feat_2": 0.504196, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_shopping_gen_36", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.86, + "time": 45.5, + "distance": 1196.08, + "gen_feat_1": 495.33, + "gen_feat_2": 0.498326, + "gen_feat_3": 486.34 + } + }, + { + "id": "t_shopping_gen_37", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.59, + "time": 44.26, + "distance": 1203.59, + "gen_feat_1": 496.81, + "gen_feat_2": 0.510331, + "gen_feat_3": 506.27 + } + }, + { + "id": "t_shopping_gen_38", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.92, + "time": 45.08, + "distance": 1203.94, + "gen_feat_1": 500.75, + "gen_feat_2": 0.49117, + "gen_feat_3": 491.78 + } + }, + { + "id": "t_shopping_gen_39", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.31, + "time": 46.16, + "distance": 1182.79, + "gen_feat_1": 497.1, + "gen_feat_2": 0.497946, + "gen_feat_3": 512.02 + } + }, + { + "id": "t_shopping_gen_40", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.54, + "time": 44.22, + "distance": 1217.58, + "gen_feat_1": 514.19, + "gen_feat_2": 0.507653, + "gen_feat_3": 502.34 + } + }, + { + "id": "t_shopping_gen_41", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.64, + "time": 44.32, + "distance": 1196.64, + "gen_feat_1": 510.6, + "gen_feat_2": 0.510227, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_42", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.93, + "time": 46.08, + "distance": 1215.22, + "gen_feat_1": 509.33, + "gen_feat_2": 0.489128, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_43", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.94, + "time": 46.06, + "distance": 1197.83, + "gen_feat_1": 494.23, + "gen_feat_2": 0.491429, + "gen_feat_3": 512.77 + } + }, + { + "id": "t_shopping_gen_44", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.62, + "time": 44.6, + "distance": 1228.92, + "gen_feat_1": 503.07, + "gen_feat_2": 0.497061, + "gen_feat_3": 508.73 + } + }, + { + "id": "t_shopping_gen_45", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.54, + "time": 45.8, + "distance": 1230.3, + "gen_feat_1": 498.44, + "gen_feat_2": 0.491182, + "gen_feat_3": 510.12 + } + }, + { + "id": "t_shopping_gen_46", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 44.28, + "distance": 1216.64, + "gen_feat_1": 488.95, + "gen_feat_2": 0.485686, + "gen_feat_3": 513.45 + } + }, + { + "id": "t_shopping_gen_47", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.4, + "time": 44.8, + "distance": 1210.54, + "gen_feat_1": 488.83, + "gen_feat_2": 0.508023, + "gen_feat_3": 485.22 + } + }, + { + "id": "t_shopping_gen_48", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.69, + "time": 44.94, + "distance": 1204.74, + "gen_feat_1": 504.02, + "gen_feat_2": 0.485166, + "gen_feat_3": 509.28 + } + }, + { + "id": "t_shopping_gen_49", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.63, + "time": 45.76, + "distance": 1234.29, + "gen_feat_1": 496.66, + "gen_feat_2": 0.510271, + "gen_feat_3": 488.57 + } + }, + { + "id": "t_shopping_gen_50", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.54, + "time": 44.91, + "distance": 1215.96, + "gen_feat_1": 509.77, + "gen_feat_2": 0.485673, + "gen_feat_3": 502.33 + } + }, + { + "id": "t_shopping_gen_51", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.48, + "time": 46.17, + "distance": 1186.08, + "gen_feat_1": 512.11, + "gen_feat_2": 0.491803, + "gen_feat_3": 503.47 + } + }, + { + "id": "t_shopping_gen_52", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.89, + "time": 44.45, + "distance": 1194.92, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486916, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_shopping_gen_53", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.35, + "time": 44.61, + "distance": 1191.25, + "gen_feat_1": 503.61, + "gen_feat_2": 0.493221, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_shopping_gen_54", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.73, + "time": 45.54, + "distance": 1223.55, + "gen_feat_1": 494.27, + "gen_feat_2": 0.490001, + "gen_feat_3": 493.72 + } + }, + { + "id": "t_shopping_gen_55", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 44.24, + "distance": 1228.06, + "gen_feat_1": 497.25, + "gen_feat_2": 0.49955, + "gen_feat_3": 486.14 + } + }, + { + "id": "t_shopping_gen_56", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.69, + "time": 44.04, + "distance": 1224.5, + "gen_feat_1": 492.29, + "gen_feat_2": 0.500032, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_57", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.68, + "time": 46.32, + "distance": 1227.05, + "gen_feat_1": 510.63, + "gen_feat_2": 0.51217, + "gen_feat_3": 489.8 + } + }, + { + "id": "t_shopping_gen_58", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.13, + "time": 45.42, + "distance": 1231.38, + "gen_feat_1": 499.25, + "gen_feat_2": 0.502657, + "gen_feat_3": 488.16 + } + }, + { + "id": "t_shopping_gen_59", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 45.04, + "distance": 1206.58, + "gen_feat_1": 488.66, + "gen_feat_2": 0.500622, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_shopping_gen_60", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.33, + "time": 46.0, + "distance": 1170.11, + "gen_feat_1": 511.4, + "gen_feat_2": 0.49549, + "gen_feat_3": 503.71 + } + }, + { + "id": "t_shopping_gen_61", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.18, + "time": 46.1, + "distance": 1190.97, + "gen_feat_1": 498.6, + "gen_feat_2": 0.501812, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_62", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.24, + "time": 45.7, + "distance": 1164.26, + "gen_feat_1": 485.26, + "gen_feat_2": 0.49031, + "gen_feat_3": 487.45 + } + }, + { + "id": "t_shopping_gen_63", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.17, + "time": 45.97, + "distance": 1190.2, + "gen_feat_1": 511.28, + "gen_feat_2": 0.51432, + "gen_feat_3": 513.58 + } + }, + { + "id": "t_shopping_gen_64", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.73, + "time": 44.03, + "distance": 1178.97, + "gen_feat_1": 487.49, + "gen_feat_2": 0.508632, + "gen_feat_3": 500.21 + } + }, + { + "id": "t_shopping_gen_65", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.67, + "time": 43.83, + "distance": 1176.27, + "gen_feat_1": 512.03, + "gen_feat_2": 0.49815, + "gen_feat_3": 501.03 + } + }, + { + "id": "t_shopping_gen_66", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.26, + "time": 44.73, + "distance": 1220.07, + "gen_feat_1": 504.64, + "gen_feat_2": 0.502789, + "gen_feat_3": 505.95 + } + }, + { + "id": "t_shopping_gen_67", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.81, + "time": 44.73, + "distance": 1180.99, + "gen_feat_1": 491.13, + "gen_feat_2": 0.488945, + "gen_feat_3": 487.4 + } + }, + { + "id": "t_shopping_gen_68", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.86, + "time": 43.67, + "distance": 1232.56, + "gen_feat_1": 512.67, + "gen_feat_2": 0.491258, + "gen_feat_3": 495.53 + } + }, + { + "id": "t_shopping_gen_69", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.0, + "time": 45.32, + "distance": 1179.79, + "gen_feat_1": 504.7, + "gen_feat_2": 0.501825, + "gen_feat_3": 494.35 + } + }, + { + "id": "t_shopping_gen_70", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 45.99, + "distance": 1206.39, + "gen_feat_1": 497.84, + "gen_feat_2": 0.509326, + "gen_feat_3": 508.37 + } + }, + { + "id": "t_shopping_gen_71", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.89, + "time": 44.23, + "distance": 1211.83, + "gen_feat_1": 489.02, + "gen_feat_2": 0.504569, + "gen_feat_3": 486.74 + } + }, + { + "id": "t_shopping_gen_72", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.25, + "time": 43.89, + "distance": 1218.83, + "gen_feat_1": 514.57, + "gen_feat_2": 0.487312, + "gen_feat_3": 491.96 + } + }, + { + "id": "t_shopping_gen_73", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 45.64, + "distance": 1171.76, + "gen_feat_1": 499.58, + "gen_feat_2": 0.499353, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_shopping_gen_74", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.51, + "time": 45.18, + "distance": 1235.16, + "gen_feat_1": 491.35, + "gen_feat_2": 0.488032, + "gen_feat_3": 508.76 + } + }, + { + "id": "t_shopping_gen_75", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.45, + "time": 45.29, + "distance": 1185.87, + "gen_feat_1": 506.16, + "gen_feat_2": 0.494622, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_shopping_gen_76", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.11, + "time": 44.39, + "distance": 1222.53, + "gen_feat_1": 507.53, + "gen_feat_2": 0.505002, + "gen_feat_3": 503.01 + } + }, + { + "id": "t_shopping_gen_77", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.93, + "time": 46.13, + "distance": 1210.75, + "gen_feat_1": 506.27, + "gen_feat_2": 0.505682, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_shopping_gen_78", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.16, + "time": 46.07, + "distance": 1210.7, + "gen_feat_1": 508.56, + "gen_feat_2": 0.487189, + "gen_feat_3": 504.12 + } + }, + { + "id": "t_shopping_gen_79", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.03, + "time": 45.66, + "distance": 1190.96, + "gen_feat_1": 489.72, + "gen_feat_2": 0.488214, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_shopping_gen_80", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.77, + "time": 45.73, + "distance": 1226.46, + "gen_feat_1": 498.85, + "gen_feat_2": 0.50612, + "gen_feat_3": 508.83 + } + }, + { + "id": "t_shopping_gen_81", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.19, + "time": 44.4, + "distance": 1207.41, + "gen_feat_1": 512.69, + "gen_feat_2": 0.49773, + "gen_feat_3": 499.57 + } + }, + { + "id": "t_shopping_gen_82", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.91, + "time": 45.81, + "distance": 1232.14, + "gen_feat_1": 501.37, + "gen_feat_2": 0.501413, + "gen_feat_3": 509.02 + } + }, + { + "id": "t_shopping_gen_83", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.46, + "time": 45.7, + "distance": 1201.06, + "gen_feat_1": 507.37, + "gen_feat_2": 0.512514, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_84", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.46, + "time": 45.7, + "distance": 1176.63, + "gen_feat_1": 500.57, + "gen_feat_2": 0.512907, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_shopping_gen_85", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.3, + "time": 44.77, + "distance": 1227.54, + "gen_feat_1": 488.72, + "gen_feat_2": 0.491267, + "gen_feat_3": 504.72 + } + }, + { + "id": "t_shopping_gen_86", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.53, + "time": 44.82, + "distance": 1227.19, + "gen_feat_1": 495.19, + "gen_feat_2": 0.506807, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_shopping_gen_87", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.76, + "time": 45.19, + "distance": 1197.27, + "gen_feat_1": 492.23, + "gen_feat_2": 0.502276, + "gen_feat_3": 497.83 + } + }, + { + "id": "t_shopping_gen_88", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.51, + "time": 46.32, + "distance": 1202.27, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500008, + "gen_feat_3": 494.37 + } + }, + { + "id": "t_shopping_gen_89", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.31, + "time": 45.09, + "distance": 1196.05, + "gen_feat_1": 488.52, + "gen_feat_2": 0.501783, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_90", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.15, + "time": 45.09, + "distance": 1187.36, + "gen_feat_1": 510.87, + "gen_feat_2": 0.48952, + "gen_feat_3": 487.44 + } + }, + { + "id": "t_shopping_gen_91", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.98, + "time": 44.28, + "distance": 1230.46, + "gen_feat_1": 494.85, + "gen_feat_2": 0.49072, + "gen_feat_3": 507.33 + } + }, + { + "id": "t_shopping_gen_92", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.46, + "time": 44.78, + "distance": 1190.65, + "gen_feat_1": 511.14, + "gen_feat_2": 0.491965, + "gen_feat_3": 510.07 + } + }, + { + "id": "t_shopping_gen_93", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 44.16, + "distance": 1232.76, + "gen_feat_1": 491.76, + "gen_feat_2": 0.49386, + "gen_feat_3": 489.99 + } + }, + { + "id": "t_shopping_gen_94", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.09, + "time": 45.07, + "distance": 1187.9, + "gen_feat_1": 500.36, + "gen_feat_2": 0.505173, + "gen_feat_3": 512.28 + } + }, + { + "id": "t_shopping_gen_95", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.29, + "time": 44.73, + "distance": 1224.17, + "gen_feat_1": 507.58, + "gen_feat_2": 0.48708, + "gen_feat_3": 511.59 + } + }, + { + "id": "t_shopping_gen_96", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.53, + "time": 43.89, + "distance": 1206.53, + "gen_feat_1": 493.71, + "gen_feat_2": 0.505153, + "gen_feat_3": 502.61 + } + }, + { + "id": "t_shopping_gen_97", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.6, + "time": 45.25, + "distance": 1198.77, + "gen_feat_1": 499.74, + "gen_feat_2": 0.499805, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_shopping_gen_98", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.94, + "time": 45.61, + "distance": 1168.51, + "gen_feat_1": 491.6, + "gen_feat_2": 0.511011, + "gen_feat_3": 491.45 + } + }, + { + "id": "t_shopping_gen_99", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.76, + "time": 45.99, + "distance": 1192.67, + "gen_feat_1": 500.07, + "gen_feat_2": 0.491787, + "gen_feat_3": 488.2 + } + }, + { + "id": "t_movie_gen_2", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.81, + "time": 138.02, + "distance": 1654.01, + "gen_feat_1": 503.91, + "gen_feat_2": 0.502664, + "gen_feat_3": 506.8 + } + }, + { + "id": "t_movie_gen_3", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.98, + "time": 133.32, + "distance": 1664.29, + "gen_feat_1": 491.47, + "gen_feat_2": 0.500325, + "gen_feat_3": 496.28 + } + }, + { + "id": "t_movie_gen_4", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.11, + "time": 136.06, + "distance": 1704.88, + "gen_feat_1": 505.19, + "gen_feat_2": 0.509953, + "gen_feat_3": 499.19 + } + }, + { + "id": "t_movie_gen_5", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.17, + "time": 136.4, + "distance": 1724.13, + "gen_feat_1": 511.77, + "gen_feat_2": 0.505076, + "gen_feat_3": 491.0 + } + }, + { + "id": "t_movie_gen_6", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.2, + "time": 137.15, + "distance": 1664.63, + "gen_feat_1": 514.48, + "gen_feat_2": 0.503771, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_movie_gen_7", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.16, + "time": 135.61, + "distance": 1726.58, + "gen_feat_1": 493.34, + "gen_feat_2": 0.493128, + "gen_feat_3": 491.4 + } + }, + { + "id": "t_movie_gen_8", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.91, + "time": 135.69, + "distance": 1678.5, + "gen_feat_1": 493.49, + "gen_feat_2": 0.506584, + "gen_feat_3": 491.95 + } + }, + { + "id": "t_movie_gen_9", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.09, + "time": 132.47, + "distance": 1682.74, + "gen_feat_1": 513.37, + "gen_feat_2": 0.496243, + "gen_feat_3": 510.52 + } + }, + { + "id": "t_movie_gen_10", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.25, + "time": 134.94, + "distance": 1683.72, + "gen_feat_1": 493.66, + "gen_feat_2": 0.502149, + "gen_feat_3": 491.38 + } + }, + { + "id": "t_movie_gen_11", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 132.2, + "distance": 1677.4, + "gen_feat_1": 513.51, + "gen_feat_2": 0.512663, + "gen_feat_3": 496.77 + } + }, + { + "id": "t_movie_gen_12", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.02, + "time": 136.12, + "distance": 1683.25, + "gen_feat_1": 486.72, + "gen_feat_2": 0.48763, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_movie_gen_13", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 131.91, + "distance": 1710.85, + "gen_feat_1": 493.33, + "gen_feat_2": 0.499006, + "gen_feat_3": 497.58 + } + }, + { + "id": "t_movie_gen_14", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.85, + "time": 137.69, + "distance": 1738.0, + "gen_feat_1": 501.65, + "gen_feat_2": 0.507629, + "gen_feat_3": 509.86 + } + }, + { + "id": "t_movie_gen_15", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.02, + "time": 133.61, + "distance": 1660.2, + "gen_feat_1": 512.64, + "gen_feat_2": 0.487548, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_movie_gen_16", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.2, + "time": 132.6, + "distance": 1669.36, + "gen_feat_1": 490.54, + "gen_feat_2": 0.507088, + "gen_feat_3": 496.37 + } + }, + { + "id": "t_movie_gen_17", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.25, + "time": 138.2, + "distance": 1711.42, + "gen_feat_1": 497.15, + "gen_feat_2": 0.513509, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_movie_gen_18", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.76, + "time": 136.31, + "distance": 1749.75, + "gen_feat_1": 514.83, + "gen_feat_2": 0.50335, + "gen_feat_3": 503.33 + } + }, + { + "id": "t_movie_gen_19", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 131.68, + "distance": 1656.52, + "gen_feat_1": 487.37, + "gen_feat_2": 0.493627, + "gen_feat_3": 508.19 + } + }, + { + "id": "t_movie_gen_20", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.9, + "time": 137.27, + "distance": 1709.53, + "gen_feat_1": 497.44, + "gen_feat_2": 0.486038, + "gen_feat_3": 502.32 + } + }, + { + "id": "t_movie_gen_21", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.83, + "time": 136.88, + "distance": 1708.94, + "gen_feat_1": 492.6, + "gen_feat_2": 0.496495, + "gen_feat_3": 490.83 + } + }, + { + "id": "t_movie_gen_22", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.12, + "time": 133.07, + "distance": 1711.62, + "gen_feat_1": 493.34, + "gen_feat_2": 0.499182, + "gen_feat_3": 499.28 + } + }, + { + "id": "t_movie_gen_23", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.12, + "time": 134.21, + "distance": 1736.25, + "gen_feat_1": 503.64, + "gen_feat_2": 0.5068, + "gen_feat_3": 489.21 + } + }, + { + "id": "t_movie_gen_24", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 132.64, + "distance": 1664.88, + "gen_feat_1": 510.09, + "gen_feat_2": 0.510289, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_movie_gen_25", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.1, + "time": 137.12, + "distance": 1701.34, + "gen_feat_1": 501.06, + "gen_feat_2": 0.49893, + "gen_feat_3": 507.73 + } + }, + { + "id": "t_movie_gen_26", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 136.45, + "distance": 1678.04, + "gen_feat_1": 494.8, + "gen_feat_2": 0.485118, + "gen_feat_3": 508.86 + } + }, + { + "id": "t_movie_gen_27", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.83, + "time": 134.67, + "distance": 1694.92, + "gen_feat_1": 503.64, + "gen_feat_2": 0.511029, + "gen_feat_3": 505.48 + } + }, + { + "id": "t_movie_gen_28", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.96, + "time": 138.62, + "distance": 1659.13, + "gen_feat_1": 491.47, + "gen_feat_2": 0.511429, + "gen_feat_3": 500.08 + } + }, + { + "id": "t_movie_gen_29", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.76, + "time": 138.64, + "distance": 1697.07, + "gen_feat_1": 498.44, + "gen_feat_2": 0.509025, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_movie_gen_30", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.39, + "distance": 1730.3, + "gen_feat_1": 510.02, + "gen_feat_2": 0.491101, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_31", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.28, + "time": 131.41, + "distance": 1685.65, + "gen_feat_1": 490.64, + "gen_feat_2": 0.485642, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_movie_gen_32", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.93, + "time": 134.98, + "distance": 1695.11, + "gen_feat_1": 501.21, + "gen_feat_2": 0.50543, + "gen_feat_3": 499.51 + } + }, + { + "id": "t_movie_gen_33", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.87, + "time": 137.83, + "distance": 1715.38, + "gen_feat_1": 513.71, + "gen_feat_2": 0.493568, + "gen_feat_3": 514.01 + } + }, + { + "id": "t_movie_gen_34", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.81, + "time": 132.4, + "distance": 1663.09, + "gen_feat_1": 506.91, + "gen_feat_2": 0.510638, + "gen_feat_3": 501.83 + } + }, + { + "id": "t_movie_gen_35", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.24, + "time": 136.79, + "distance": 1694.27, + "gen_feat_1": 510.84, + "gen_feat_2": 0.507452, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_movie_gen_36", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.16, + "time": 136.15, + "distance": 1670.24, + "gen_feat_1": 502.99, + "gen_feat_2": 0.495856, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_37", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.3, + "time": 136.48, + "distance": 1719.06, + "gen_feat_1": 512.77, + "gen_feat_2": 0.488773, + "gen_feat_3": 505.19 + } + }, + { + "id": "t_movie_gen_38", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.89, + "time": 137.8, + "distance": 1682.43, + "gen_feat_1": 514.67, + "gen_feat_2": 0.508214, + "gen_feat_3": 504.71 + } + }, + { + "id": "t_movie_gen_39", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.88, + "time": 136.94, + "distance": 1652.85, + "gen_feat_1": 499.19, + "gen_feat_2": 0.500729, + "gen_feat_3": 511.08 + } + }, + { + "id": "t_movie_gen_40", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.75, + "time": 136.81, + "distance": 1673.83, + "gen_feat_1": 510.5, + "gen_feat_2": 0.496266, + "gen_feat_3": 512.35 + } + }, + { + "id": "t_movie_gen_41", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.84, + "time": 133.13, + "distance": 1698.79, + "gen_feat_1": 504.79, + "gen_feat_2": 0.491761, + "gen_feat_3": 489.88 + } + }, + { + "id": "t_movie_gen_42", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.79, + "time": 132.71, + "distance": 1654.02, + "gen_feat_1": 488.54, + "gen_feat_2": 0.496646, + "gen_feat_3": 506.89 + } + }, + { + "id": "t_movie_gen_43", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.03, + "time": 135.73, + "distance": 1687.52, + "gen_feat_1": 489.12, + "gen_feat_2": 0.50799, + "gen_feat_3": 499.94 + } + }, + { + "id": "t_movie_gen_44", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.09, + "time": 138.68, + "distance": 1703.05, + "gen_feat_1": 510.12, + "gen_feat_2": 0.485551, + "gen_feat_3": 502.13 + } + }, + { + "id": "t_movie_gen_45", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.86, + "time": 133.42, + "distance": 1652.65, + "gen_feat_1": 488.6, + "gen_feat_2": 0.510397, + "gen_feat_3": 509.98 + } + }, + { + "id": "t_movie_gen_46", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.97, + "time": 131.94, + "distance": 1673.56, + "gen_feat_1": 486.56, + "gen_feat_2": 0.505523, + "gen_feat_3": 501.82 + } + }, + { + "id": "t_movie_gen_47", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.0, + "time": 133.55, + "distance": 1671.34, + "gen_feat_1": 488.32, + "gen_feat_2": 0.49915, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_movie_gen_48", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.06, + "time": 138.36, + "distance": 1677.66, + "gen_feat_1": 497.58, + "gen_feat_2": 0.497849, + "gen_feat_3": 488.29 + } + }, + { + "id": "t_movie_gen_49", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 133.95, + "distance": 1742.48, + "gen_feat_1": 495.5, + "gen_feat_2": 0.511503, + "gen_feat_3": 491.31 + } + }, + { + "id": "t_movie_gen_50", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.77, + "time": 135.54, + "distance": 1710.41, + "gen_feat_1": 487.97, + "gen_feat_2": 0.508317, + "gen_feat_3": 490.49 + } + }, + { + "id": "t_movie_gen_51", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.77, + "time": 135.9, + "distance": 1664.29, + "gen_feat_1": 513.14, + "gen_feat_2": 0.507714, + "gen_feat_3": 487.99 + } + }, + { + "id": "t_movie_gen_52", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.74, + "time": 133.36, + "distance": 1679.04, + "gen_feat_1": 502.14, + "gen_feat_2": 0.489374, + "gen_feat_3": 501.0 + } + }, + { + "id": "t_movie_gen_53", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.75, + "time": 137.75, + "distance": 1727.9, + "gen_feat_1": 494.43, + "gen_feat_2": 0.492795, + "gen_feat_3": 507.56 + } + }, + { + "id": "t_movie_gen_54", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 137.23, + "distance": 1749.88, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514964, + "gen_feat_3": 513.51 + } + }, + { + "id": "t_movie_gen_55", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.27, + "time": 131.7, + "distance": 1671.69, + "gen_feat_1": 491.71, + "gen_feat_2": 0.507637, + "gen_feat_3": 496.63 + } + }, + { + "id": "t_movie_gen_56", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.25, + "time": 133.82, + "distance": 1744.69, + "gen_feat_1": 513.96, + "gen_feat_2": 0.486719, + "gen_feat_3": 505.59 + } + }, + { + "id": "t_movie_gen_57", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.99, + "distance": 1687.02, + "gen_feat_1": 495.73, + "gen_feat_2": 0.497053, + "gen_feat_3": 485.08 + } + }, + { + "id": "t_movie_gen_58", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 134.0, + "distance": 1717.93, + "gen_feat_1": 498.58, + "gen_feat_2": 0.514512, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_movie_gen_59", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 135.99, + "distance": 1669.61, + "gen_feat_1": 506.91, + "gen_feat_2": 0.486343, + "gen_feat_3": 513.29 + } + }, + { + "id": "t_movie_gen_60", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 137.16, + "distance": 1727.65, + "gen_feat_1": 511.78, + "gen_feat_2": 0.498191, + "gen_feat_3": 495.09 + } + }, + { + "id": "t_movie_gen_61", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.06, + "time": 131.51, + "distance": 1688.72, + "gen_feat_1": 501.65, + "gen_feat_2": 0.503774, + "gen_feat_3": 494.98 + } + }, + { + "id": "t_movie_gen_62", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 134.94, + "distance": 1688.34, + "gen_feat_1": 486.17, + "gen_feat_2": 0.506252, + "gen_feat_3": 499.8 + } + }, + { + "id": "t_movie_gen_63", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.0, + "time": 132.52, + "distance": 1696.65, + "gen_feat_1": 514.69, + "gen_feat_2": 0.493209, + "gen_feat_3": 485.24 + } + }, + { + "id": "t_movie_gen_64", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.73, + "time": 131.33, + "distance": 1699.32, + "gen_feat_1": 494.73, + "gen_feat_2": 0.500638, + "gen_feat_3": 507.36 + } + }, + { + "id": "t_movie_gen_65", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.28, + "time": 135.57, + "distance": 1672.37, + "gen_feat_1": 512.61, + "gen_feat_2": 0.49003, + "gen_feat_3": 498.67 + } + }, + { + "id": "t_movie_gen_66", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.81, + "time": 133.8, + "distance": 1700.55, + "gen_feat_1": 512.0, + "gen_feat_2": 0.486179, + "gen_feat_3": 501.33 + } + }, + { + "id": "t_movie_gen_67", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.03, + "time": 131.77, + "distance": 1745.74, + "gen_feat_1": 503.3, + "gen_feat_2": 0.51441, + "gen_feat_3": 486.9 + } + }, + { + "id": "t_movie_gen_68", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.9, + "time": 137.31, + "distance": 1655.07, + "gen_feat_1": 485.6, + "gen_feat_2": 0.49856, + "gen_feat_3": 495.04 + } + }, + { + "id": "t_movie_gen_69", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.19, + "time": 137.9, + "distance": 1713.23, + "gen_feat_1": 510.23, + "gen_feat_2": 0.490473, + "gen_feat_3": 492.48 + } + }, + { + "id": "t_movie_gen_70", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.92, + "time": 137.74, + "distance": 1742.03, + "gen_feat_1": 497.94, + "gen_feat_2": 0.514756, + "gen_feat_3": 487.31 + } + }, + { + "id": "t_movie_gen_71", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.28, + "time": 134.06, + "distance": 1654.96, + "gen_feat_1": 510.56, + "gen_feat_2": 0.492021, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_movie_gen_72", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 135.82, + "distance": 1738.49, + "gen_feat_1": 500.42, + "gen_feat_2": 0.493135, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_73", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 134.69, + "distance": 1663.19, + "gen_feat_1": 491.2, + "gen_feat_2": 0.505794, + "gen_feat_3": 504.69 + } + }, + { + "id": "t_movie_gen_74", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.82, + "time": 132.56, + "distance": 1679.26, + "gen_feat_1": 497.39, + "gen_feat_2": 0.485217, + "gen_feat_3": 513.12 + } + }, + { + "id": "t_movie_gen_75", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.18, + "time": 134.95, + "distance": 1745.08, + "gen_feat_1": 491.08, + "gen_feat_2": 0.495277, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_movie_gen_76", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.16, + "time": 138.62, + "distance": 1666.98, + "gen_feat_1": 501.07, + "gen_feat_2": 0.506814, + "gen_feat_3": 489.44 + } + }, + { + "id": "t_movie_gen_77", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.76, + "time": 130.95, + "distance": 1675.39, + "gen_feat_1": 513.23, + "gen_feat_2": 0.496512, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_movie_gen_78", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.99, + "time": 132.12, + "distance": 1674.54, + "gen_feat_1": 495.99, + "gen_feat_2": 0.496439, + "gen_feat_3": 506.49 + } + }, + { + "id": "t_movie_gen_79", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.84, + "time": 132.9, + "distance": 1698.58, + "gen_feat_1": 486.83, + "gen_feat_2": 0.487385, + "gen_feat_3": 489.3 + } + }, + { + "id": "t_movie_gen_80", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 135.25, + "distance": 1703.48, + "gen_feat_1": 497.71, + "gen_feat_2": 0.506091, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_movie_gen_81", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.08, + "time": 138.34, + "distance": 1706.78, + "gen_feat_1": 501.18, + "gen_feat_2": 0.503416, + "gen_feat_3": 493.11 + } + }, + { + "id": "t_movie_gen_82", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.95, + "time": 132.28, + "distance": 1658.35, + "gen_feat_1": 488.13, + "gen_feat_2": 0.514958, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_83", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 135.04, + "distance": 1663.79, + "gen_feat_1": 495.07, + "gen_feat_2": 0.489223, + "gen_feat_3": 514.52 + } + }, + { + "id": "t_movie_gen_84", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.76, + "time": 137.41, + "distance": 1703.65, + "gen_feat_1": 504.9, + "gen_feat_2": 0.503529, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_movie_gen_85", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.08, + "time": 135.55, + "distance": 1691.79, + "gen_feat_1": 503.38, + "gen_feat_2": 0.5004, + "gen_feat_3": 510.63 + } + }, + { + "id": "t_movie_gen_86", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.24, + "time": 133.11, + "distance": 1689.53, + "gen_feat_1": 509.79, + "gen_feat_2": 0.49881, + "gen_feat_3": 488.86 + } + }, + { + "id": "t_movie_gen_87", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.89, + "time": 137.15, + "distance": 1698.06, + "gen_feat_1": 503.82, + "gen_feat_2": 0.50464, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_88", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.13, + "time": 131.18, + "distance": 1660.59, + "gen_feat_1": 492.85, + "gen_feat_2": 0.514114, + "gen_feat_3": 513.82 + } + }, + { + "id": "t_movie_gen_89", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.87, + "time": 135.02, + "distance": 1741.57, + "gen_feat_1": 501.92, + "gen_feat_2": 0.508398, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_90", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.28, + "time": 137.35, + "distance": 1718.09, + "gen_feat_1": 488.68, + "gen_feat_2": 0.49537, + "gen_feat_3": 493.95 + } + }, + { + "id": "t_movie_gen_91", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 137.3, + "distance": 1693.34, + "gen_feat_1": 493.19, + "gen_feat_2": 0.495672, + "gen_feat_3": 488.25 + } + }, + { + "id": "t_movie_gen_92", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.83, + "time": 137.58, + "distance": 1744.3, + "gen_feat_1": 491.56, + "gen_feat_2": 0.498387, + "gen_feat_3": 511.69 + } + }, + { + "id": "t_movie_gen_93", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.91, + "time": 133.34, + "distance": 1702.93, + "gen_feat_1": 488.01, + "gen_feat_2": 0.502779, + "gen_feat_3": 491.18 + } + }, + { + "id": "t_movie_gen_94", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 134.1, + "distance": 1680.7, + "gen_feat_1": 497.7, + "gen_feat_2": 0.497436, + "gen_feat_3": 502.47 + } + }, + { + "id": "t_movie_gen_95", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 136.67, + "distance": 1705.0, + "gen_feat_1": 488.28, + "gen_feat_2": 0.487878, + "gen_feat_3": 495.8 + } + }, + { + "id": "t_movie_gen_96", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.9, + "time": 134.07, + "distance": 1659.49, + "gen_feat_1": 492.47, + "gen_feat_2": 0.492451, + "gen_feat_3": 511.78 + } + }, + { + "id": "t_movie_gen_97", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.21, + "time": 134.31, + "distance": 1734.61, + "gen_feat_1": 493.2, + "gen_feat_2": 0.488477, + "gen_feat_3": 503.93 + } + }, + { + "id": "t_movie_gen_98", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 135.67, + "distance": 1729.26, + "gen_feat_1": 489.64, + "gen_feat_2": 0.491387, + "gen_feat_3": 506.86 + } + }, + { + "id": "t_movie_gen_99", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.79, + "time": 133.64, + "distance": 1673.71, + "gen_feat_1": 505.04, + "gen_feat_2": 0.505422, + "gen_feat_3": 513.37 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_dining", + "kind": "TASK", + "task_id": "t_dining" + }, + { + "id": "n_shopping", + "kind": "TASK", + "task_id": "t_shopping" + }, + { + "id": "n_movie", + "kind": "TASK", + "task_id": "t_movie" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "time": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "distance": { + "neutral": 0, + "compose": { + "seq": { + "fn": "MAX" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "c_within_2km", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "distance", + "op": "<=", + "value": 2000 + }, + { + "id": "c_time_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "time", + "op": "<=", + "value": 240, + "hard": false + }, + { + "id": "c_cost_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 100, + "hard": false + }, + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 50.07, + "hard": true + }, + { + "id": "gen_c_local_t_dining_time_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_dining" + ], + "attribute_id": "time", + "op": "<=", + "value": 59.79, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_dining", + "t_shopping" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_dining", + "t_movie" + ], + "hard": true + } + ], + "objective": { + "type": "MONO", + "targets": [ + "cost", + "distance", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "time" + ], + "weights": { + "cost": 0.17, + "distance": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "time": 0.16 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/zhang2014-entertainment-planner-running-example_mono_utility_soft.json b/experimentation/instances/zhang2014-entertainment-planner-running-example_mono_utility_soft.json new file mode 100644 index 0000000..ded15cd --- /dev/null +++ b/experimentation/instances/zhang2014-entertainment-planner-running-example_mono_utility_soft.json @@ -0,0 +1,4541 @@ +{ + "metadata": { + "id": "zhang2014-entertainment-planner-running-example_mono_utility_soft", + "name": "Personal Entertainment Planner (Zhang et al. 2014) [mono_utility, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:05Z", + "description": "Modeled from the motivating example in 'Context-aware Generic Service Discovery and Service Composition' (IEEE MobServ 2014).", + "paper": { + "title": "Context-aware Generic Service Discovery and Service Composition", + "authors": "Y. Zhang et al.", + "year": 2014, + "doi": "10.1109/MobServ.2014.27" + } + }, + "features": [ + { + "id": "cost", + "name": "Total money cost (USD)", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "time", + "name": "Total time cost (minutes)", + "direction": "MINIMIZE", + "unit": "min", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1440 + } + }, + { + "id": "distance", + "name": "Distance from user's current location (meters)", + "direction": "MINIMIZE", + "unit": "m", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 50000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_rest_autre_saison", + "name": "Restaurant L’Autre Saison" + }, + { + "id": "p_cinema_banque_scotia", + "name": "Cinema Banque Scotia Montreal" + }, + { + "id": "p_seven_night_club", + "name": "Seven Night Club" + }, + { + "id": "p_local_shopping", + "name": "Local Shopping (nearby venue)" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_dining", + "name": "Restaurant / Dining activity" + }, + { + "id": "t_shopping", + "name": "Shopping activity" + }, + { + "id": "t_movie", + "name": "Movie activity" + } + ], + "candidates": [ + { + "id": "c_dining_autre_saison", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison", + "features": { + "cost": 20, + "time": 60, + "distance": 1600, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_dining_seven_night_club", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Seven Night Club", + "features": { + "cost": 20, + "time": 60, + "distance": 1800, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopping_local", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue", + "features": { + "cost": 20, + "time": 45, + "distance": 1200, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_movie_the_help_banque_scotia", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal", + "features": { + "cost": 10, + "time": 135, + "distance": 1700, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_dining_gen_1", + "task_id": "t_dining", + "provider_id": "p_gen_shared", + "name": "Dinner at Restaurant L’Autre Saison (Gen Shared)", + "features": { + "cost": 20.2, + "time": 59.79, + "distance": 1570.05, + "gen_feat_1": 508.24, + "gen_feat_2": 0.514901, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_shopping_gen_1", + "task_id": "t_shopping", + "provider_id": "p_gen_shared", + "name": "Shopping at a nearby venue (Gen Shared)", + "features": { + "cost": 19.87, + "time": 44.98, + "distance": 1189.95, + "gen_feat_1": 485.24, + "gen_feat_2": 0.486287, + "gen_feat_3": 500.42 + } + }, + { + "id": "t_movie_gen_1", + "task_id": "t_movie", + "provider_id": "p_gen_shared", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen Shared)", + "features": { + "cost": 9.82, + "time": 134.28, + "distance": 1742.9, + "gen_feat_1": 512.03, + "gen_feat_2": 0.505972, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_dining_gen_2", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.53, + "time": 59.13, + "distance": 1559.02, + "gen_feat_1": 498.66, + "gen_feat_2": 0.488957, + "gen_feat_3": 503.61 + } + }, + { + "id": "t_dining_gen_3", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.94, + "time": 58.5, + "distance": 1591.09, + "gen_feat_1": 495.96, + "gen_feat_2": 0.504969, + "gen_feat_3": 506.77 + } + }, + { + "id": "t_dining_gen_4", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.8, + "time": 61.46, + "distance": 1629.91, + "gen_feat_1": 510.53, + "gen_feat_2": 0.508, + "gen_feat_3": 491.98 + } + }, + { + "id": "t_dining_gen_5", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.22, + "time": 60.39, + "distance": 1564.48, + "gen_feat_1": 491.41, + "gen_feat_2": 0.490673, + "gen_feat_3": 490.61 + } + }, + { + "id": "t_dining_gen_6", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.38, + "time": 58.67, + "distance": 1626.15, + "gen_feat_1": 488.5, + "gen_feat_2": 0.49348, + "gen_feat_3": 495.75 + } + }, + { + "id": "t_dining_gen_7", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.18, + "time": 60.72, + "distance": 1555.22, + "gen_feat_1": 505.8, + "gen_feat_2": 0.506719, + "gen_feat_3": 499.33 + } + }, + { + "id": "t_dining_gen_8", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.43, + "time": 59.64, + "distance": 1598.13, + "gen_feat_1": 503.89, + "gen_feat_2": 0.506945, + "gen_feat_3": 508.17 + } + }, + { + "id": "t_dining_gen_9", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.64, + "time": 60.54, + "distance": 1604.33, + "gen_feat_1": 486.84, + "gen_feat_2": 0.506628, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_dining_gen_10", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 60.17, + "distance": 1616.85, + "gen_feat_1": 507.44, + "gen_feat_2": 0.489997, + "gen_feat_3": 502.16 + } + }, + { + "id": "t_dining_gen_11", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.68, + "time": 59.16, + "distance": 1620.42, + "gen_feat_1": 507.98, + "gen_feat_2": 0.488942, + "gen_feat_3": 489.19 + } + }, + { + "id": "t_dining_gen_12", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.74, + "time": 59.04, + "distance": 1602.16, + "gen_feat_1": 504.58, + "gen_feat_2": 0.489389, + "gen_feat_3": 507.41 + } + }, + { + "id": "t_dining_gen_13", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.47, + "time": 58.89, + "distance": 1622.97, + "gen_feat_1": 492.31, + "gen_feat_2": 0.503154, + "gen_feat_3": 508.55 + } + }, + { + "id": "t_dining_gen_14", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.72, + "time": 58.91, + "distance": 1626.35, + "gen_feat_1": 509.41, + "gen_feat_2": 0.490291, + "gen_feat_3": 514.74 + } + }, + { + "id": "t_dining_gen_15", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.59, + "time": 60.67, + "distance": 1631.73, + "gen_feat_1": 493.43, + "gen_feat_2": 0.498961, + "gen_feat_3": 492.15 + } + }, + { + "id": "t_dining_gen_16", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.21, + "time": 59.57, + "distance": 1621.68, + "gen_feat_1": 502.04, + "gen_feat_2": 0.491944, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_dining_gen_17", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.33, + "time": 59.99, + "distance": 1602.82, + "gen_feat_1": 513.49, + "gen_feat_2": 0.510425, + "gen_feat_3": 506.46 + } + }, + { + "id": "t_dining_gen_18", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.02, + "time": 60.13, + "distance": 1639.2, + "gen_feat_1": 498.4, + "gen_feat_2": 0.499582, + "gen_feat_3": 504.62 + } + }, + { + "id": "t_dining_gen_19", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.03, + "time": 60.73, + "distance": 1642.13, + "gen_feat_1": 507.63, + "gen_feat_2": 0.500514, + "gen_feat_3": 495.73 + } + }, + { + "id": "t_dining_gen_20", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.33, + "time": 59.96, + "distance": 1568.96, + "gen_feat_1": 488.36, + "gen_feat_2": 0.514752, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_dining_gen_21", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.8, + "time": 58.42, + "distance": 1555.46, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486429, + "gen_feat_3": 488.41 + } + }, + { + "id": "t_dining_gen_22", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.66, + "time": 61.62, + "distance": 1580.67, + "gen_feat_1": 491.06, + "gen_feat_2": 0.506184, + "gen_feat_3": 501.23 + } + }, + { + "id": "t_dining_gen_23", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.42, + "time": 61.78, + "distance": 1622.72, + "gen_feat_1": 490.83, + "gen_feat_2": 0.489949, + "gen_feat_3": 487.73 + } + }, + { + "id": "t_dining_gen_24", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.71, + "time": 59.51, + "distance": 1580.85, + "gen_feat_1": 501.15, + "gen_feat_2": 0.50297, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_25", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.42, + "time": 61.41, + "distance": 1578.66, + "gen_feat_1": 507.39, + "gen_feat_2": 0.499268, + "gen_feat_3": 490.28 + } + }, + { + "id": "t_dining_gen_26", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.55, + "time": 58.26, + "distance": 1560.85, + "gen_feat_1": 492.17, + "gen_feat_2": 0.492399, + "gen_feat_3": 511.94 + } + }, + { + "id": "t_dining_gen_27", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.48, + "time": 58.34, + "distance": 1631.2, + "gen_feat_1": 498.39, + "gen_feat_2": 0.490821, + "gen_feat_3": 491.03 + } + }, + { + "id": "t_dining_gen_28", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.04, + "time": 61.28, + "distance": 1606.8, + "gen_feat_1": 512.73, + "gen_feat_2": 0.509267, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_dining_gen_29", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.76, + "time": 60.3, + "distance": 1569.61, + "gen_feat_1": 490.22, + "gen_feat_2": 0.496831, + "gen_feat_3": 496.53 + } + }, + { + "id": "t_dining_gen_30", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.71, + "time": 60.3, + "distance": 1623.3, + "gen_feat_1": 500.21, + "gen_feat_2": 0.496569, + "gen_feat_3": 498.99 + } + }, + { + "id": "t_dining_gen_31", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.86, + "time": 59.05, + "distance": 1588.58, + "gen_feat_1": 485.96, + "gen_feat_2": 0.512749, + "gen_feat_3": 498.55 + } + }, + { + "id": "t_dining_gen_32", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.8, + "time": 59.8, + "distance": 1560.3, + "gen_feat_1": 512.24, + "gen_feat_2": 0.486102, + "gen_feat_3": 508.8 + } + }, + { + "id": "t_dining_gen_33", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.49, + "time": 61.12, + "distance": 1612.82, + "gen_feat_1": 506.05, + "gen_feat_2": 0.504153, + "gen_feat_3": 510.28 + } + }, + { + "id": "t_dining_gen_34", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.66, + "time": 58.74, + "distance": 1627.51, + "gen_feat_1": 494.47, + "gen_feat_2": 0.509322, + "gen_feat_3": 485.53 + } + }, + { + "id": "t_dining_gen_35", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.14, + "time": 60.57, + "distance": 1626.08, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513739, + "gen_feat_3": 510.69 + } + }, + { + "id": "t_dining_gen_36", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.57, + "time": 58.38, + "distance": 1610.88, + "gen_feat_1": 495.23, + "gen_feat_2": 0.509726, + "gen_feat_3": 512.08 + } + }, + { + "id": "t_dining_gen_37", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.41, + "distance": 1575.46, + "gen_feat_1": 512.15, + "gen_feat_2": 0.492042, + "gen_feat_3": 505.13 + } + }, + { + "id": "t_dining_gen_38", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.22, + "time": 59.29, + "distance": 1557.64, + "gen_feat_1": 489.83, + "gen_feat_2": 0.49146, + "gen_feat_3": 495.3 + } + }, + { + "id": "t_dining_gen_39", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.59, + "time": 61.53, + "distance": 1562.65, + "gen_feat_1": 495.8, + "gen_feat_2": 0.496923, + "gen_feat_3": 507.91 + } + }, + { + "id": "t_dining_gen_40", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.43, + "time": 60.01, + "distance": 1604.0, + "gen_feat_1": 500.49, + "gen_feat_2": 0.514685, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_41", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.58, + "time": 60.72, + "distance": 1645.52, + "gen_feat_1": 487.19, + "gen_feat_2": 0.508959, + "gen_feat_3": 497.39 + } + }, + { + "id": "t_dining_gen_42", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.2, + "time": 59.26, + "distance": 1581.92, + "gen_feat_1": 509.7, + "gen_feat_2": 0.513201, + "gen_feat_3": 491.13 + } + }, + { + "id": "t_dining_gen_43", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.45, + "time": 60.26, + "distance": 1568.18, + "gen_feat_1": 493.86, + "gen_feat_2": 0.514555, + "gen_feat_3": 489.48 + } + }, + { + "id": "t_dining_gen_44", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.58, + "time": 58.5, + "distance": 1617.8, + "gen_feat_1": 491.08, + "gen_feat_2": 0.513671, + "gen_feat_3": 486.88 + } + }, + { + "id": "t_dining_gen_45", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.68, + "time": 61.23, + "distance": 1579.97, + "gen_feat_1": 509.82, + "gen_feat_2": 0.504088, + "gen_feat_3": 512.95 + } + }, + { + "id": "t_dining_gen_46", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 60.56, + "distance": 1641.45, + "gen_feat_1": 499.89, + "gen_feat_2": 0.510488, + "gen_feat_3": 491.3 + } + }, + { + "id": "t_dining_gen_47", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.94, + "time": 58.84, + "distance": 1629.37, + "gen_feat_1": 494.2, + "gen_feat_2": 0.49711, + "gen_feat_3": 496.8 + } + }, + { + "id": "t_dining_gen_48", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.23, + "time": 58.97, + "distance": 1607.14, + "gen_feat_1": 485.39, + "gen_feat_2": 0.485086, + "gen_feat_3": 504.57 + } + }, + { + "id": "t_dining_gen_49", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.47, + "time": 59.57, + "distance": 1615.57, + "gen_feat_1": 495.03, + "gen_feat_2": 0.503496, + "gen_feat_3": 509.51 + } + }, + { + "id": "t_dining_gen_50", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.7, + "distance": 1583.69, + "gen_feat_1": 489.31, + "gen_feat_2": 0.498993, + "gen_feat_3": 498.25 + } + }, + { + "id": "t_dining_gen_51", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.06, + "time": 60.11, + "distance": 1630.7, + "gen_feat_1": 507.83, + "gen_feat_2": 0.497927, + "gen_feat_3": 485.62 + } + }, + { + "id": "t_dining_gen_52", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.53, + "time": 58.59, + "distance": 1646.13, + "gen_feat_1": 489.54, + "gen_feat_2": 0.503777, + "gen_feat_3": 487.65 + } + }, + { + "id": "t_dining_gen_53", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.9, + "time": 58.5, + "distance": 1634.44, + "gen_feat_1": 514.43, + "gen_feat_2": 0.508093, + "gen_feat_3": 499.44 + } + }, + { + "id": "t_dining_gen_54", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.18, + "time": 58.68, + "distance": 1576.83, + "gen_feat_1": 491.93, + "gen_feat_2": 0.485409, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_dining_gen_55", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.0, + "distance": 1581.79, + "gen_feat_1": 489.92, + "gen_feat_2": 0.49016, + "gen_feat_3": 513.4 + } + }, + { + "id": "t_dining_gen_56", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.18, + "time": 61.73, + "distance": 1637.68, + "gen_feat_1": 492.48, + "gen_feat_2": 0.497966, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_dining_gen_57", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.2, + "time": 61.78, + "distance": 1646.08, + "gen_feat_1": 508.92, + "gen_feat_2": 0.500426, + "gen_feat_3": 499.7 + } + }, + { + "id": "t_dining_gen_58", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.57, + "time": 59.32, + "distance": 1580.58, + "gen_feat_1": 509.74, + "gen_feat_2": 0.510379, + "gen_feat_3": 512.86 + } + }, + { + "id": "t_dining_gen_59", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.54, + "time": 59.3, + "distance": 1570.05, + "gen_feat_1": 486.4, + "gen_feat_2": 0.503502, + "gen_feat_3": 498.65 + } + }, + { + "id": "t_dining_gen_60", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.18, + "time": 61.43, + "distance": 1636.11, + "gen_feat_1": 485.66, + "gen_feat_2": 0.498532, + "gen_feat_3": 506.32 + } + }, + { + "id": "t_dining_gen_61", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.01, + "time": 59.61, + "distance": 1626.73, + "gen_feat_1": 507.2, + "gen_feat_2": 0.505098, + "gen_feat_3": 499.85 + } + }, + { + "id": "t_dining_gen_62", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.22, + "time": 59.78, + "distance": 1646.36, + "gen_feat_1": 500.64, + "gen_feat_2": 0.500049, + "gen_feat_3": 504.88 + } + }, + { + "id": "t_dining_gen_63", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.11, + "time": 59.7, + "distance": 1621.52, + "gen_feat_1": 494.18, + "gen_feat_2": 0.498313, + "gen_feat_3": 506.17 + } + }, + { + "id": "t_dining_gen_64", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.71, + "time": 61.36, + "distance": 1568.12, + "gen_feat_1": 493.75, + "gen_feat_2": 0.505406, + "gen_feat_3": 512.82 + } + }, + { + "id": "t_dining_gen_65", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.4, + "time": 58.28, + "distance": 1604.89, + "gen_feat_1": 487.06, + "gen_feat_2": 0.502445, + "gen_feat_3": 511.12 + } + }, + { + "id": "t_dining_gen_66", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 59.57, + "distance": 1581.66, + "gen_feat_1": 513.25, + "gen_feat_2": 0.493068, + "gen_feat_3": 505.54 + } + }, + { + "id": "t_dining_gen_67", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.21, + "time": 60.81, + "distance": 1606.42, + "gen_feat_1": 493.36, + "gen_feat_2": 0.50459, + "gen_feat_3": 493.01 + } + }, + { + "id": "t_dining_gen_68", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 59.09, + "distance": 1611.43, + "gen_feat_1": 505.83, + "gen_feat_2": 0.502644, + "gen_feat_3": 504.4 + } + }, + { + "id": "t_dining_gen_69", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.92, + "time": 61.04, + "distance": 1579.9, + "gen_feat_1": 512.7, + "gen_feat_2": 0.488813, + "gen_feat_3": 500.85 + } + }, + { + "id": "t_dining_gen_70", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.74, + "time": 59.83, + "distance": 1615.86, + "gen_feat_1": 505.67, + "gen_feat_2": 0.48967, + "gen_feat_3": 503.59 + } + }, + { + "id": "t_dining_gen_71", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 61.74, + "distance": 1585.25, + "gen_feat_1": 495.74, + "gen_feat_2": 0.490106, + "gen_feat_3": 499.93 + } + }, + { + "id": "t_dining_gen_72", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.9, + "time": 58.61, + "distance": 1604.96, + "gen_feat_1": 509.49, + "gen_feat_2": 0.512456, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_73", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.41, + "time": 59.23, + "distance": 1631.69, + "gen_feat_1": 507.39, + "gen_feat_2": 0.504155, + "gen_feat_3": 514.37 + } + }, + { + "id": "t_dining_gen_74", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.5, + "time": 58.7, + "distance": 1628.56, + "gen_feat_1": 514.96, + "gen_feat_2": 0.498875, + "gen_feat_3": 512.16 + } + }, + { + "id": "t_dining_gen_75", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.83, + "time": 61.78, + "distance": 1589.19, + "gen_feat_1": 501.13, + "gen_feat_2": 0.504679, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_dining_gen_76", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.02, + "time": 61.78, + "distance": 1596.36, + "gen_feat_1": 511.57, + "gen_feat_2": 0.51185, + "gen_feat_3": 493.99 + } + }, + { + "id": "t_dining_gen_77", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.38, + "time": 59.52, + "distance": 1573.49, + "gen_feat_1": 513.61, + "gen_feat_2": 0.50886, + "gen_feat_3": 505.08 + } + }, + { + "id": "t_dining_gen_78", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.28, + "time": 59.03, + "distance": 1628.26, + "gen_feat_1": 513.77, + "gen_feat_2": 0.508209, + "gen_feat_3": 504.63 + } + }, + { + "id": "t_dining_gen_79", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.75, + "time": 60.98, + "distance": 1603.39, + "gen_feat_1": 510.74, + "gen_feat_2": 0.51442, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_dining_gen_80", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.34, + "time": 59.39, + "distance": 1607.15, + "gen_feat_1": 489.01, + "gen_feat_2": 0.508841, + "gen_feat_3": 503.65 + } + }, + { + "id": "t_dining_gen_81", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.78, + "time": 61.32, + "distance": 1606.79, + "gen_feat_1": 494.77, + "gen_feat_2": 0.498081, + "gen_feat_3": 490.68 + } + }, + { + "id": "t_dining_gen_82", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.0, + "time": 60.47, + "distance": 1578.03, + "gen_feat_1": 505.85, + "gen_feat_2": 0.496498, + "gen_feat_3": 494.3 + } + }, + { + "id": "t_dining_gen_83", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.59, + "time": 60.4, + "distance": 1576.41, + "gen_feat_1": 487.54, + "gen_feat_2": 0.490813, + "gen_feat_3": 506.97 + } + }, + { + "id": "t_dining_gen_84", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.45, + "time": 58.59, + "distance": 1635.41, + "gen_feat_1": 507.53, + "gen_feat_2": 0.499359, + "gen_feat_3": 511.49 + } + }, + { + "id": "t_dining_gen_85", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.55, + "time": 59.37, + "distance": 1578.95, + "gen_feat_1": 500.14, + "gen_feat_2": 0.504331, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_dining_gen_86", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.11, + "distance": 1556.1, + "gen_feat_1": 513.36, + "gen_feat_2": 0.512958, + "gen_feat_3": 493.44 + } + }, + { + "id": "t_dining_gen_87", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.26, + "time": 59.23, + "distance": 1563.62, + "gen_feat_1": 489.36, + "gen_feat_2": 0.51222, + "gen_feat_3": 503.86 + } + }, + { + "id": "t_dining_gen_88", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.46, + "time": 61.2, + "distance": 1588.14, + "gen_feat_1": 488.89, + "gen_feat_2": 0.496175, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_dining_gen_89", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.79, + "time": 58.63, + "distance": 1622.85, + "gen_feat_1": 512.62, + "gen_feat_2": 0.485995, + "gen_feat_3": 487.83 + } + }, + { + "id": "t_dining_gen_90", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.48, + "time": 58.69, + "distance": 1640.49, + "gen_feat_1": 511.37, + "gen_feat_2": 0.494218, + "gen_feat_3": 505.83 + } + }, + { + "id": "t_dining_gen_91", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.58, + "time": 58.72, + "distance": 1630.9, + "gen_feat_1": 505.33, + "gen_feat_2": 0.485446, + "gen_feat_3": 496.64 + } + }, + { + "id": "t_dining_gen_92", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.04, + "time": 59.56, + "distance": 1559.07, + "gen_feat_1": 491.21, + "gen_feat_2": 0.509726, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_93", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.84, + "time": 60.45, + "distance": 1596.68, + "gen_feat_1": 493.98, + "gen_feat_2": 0.489239, + "gen_feat_3": 493.56 + } + }, + { + "id": "t_dining_gen_94", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.56, + "time": 59.95, + "distance": 1630.28, + "gen_feat_1": 488.49, + "gen_feat_2": 0.505218, + "gen_feat_3": 491.42 + } + }, + { + "id": "t_dining_gen_95", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.97, + "time": 59.51, + "distance": 1593.3, + "gen_feat_1": 488.66, + "gen_feat_2": 0.490214, + "gen_feat_3": 504.25 + } + }, + { + "id": "t_dining_gen_96", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.85, + "time": 58.35, + "distance": 1552.26, + "gen_feat_1": 503.49, + "gen_feat_2": 0.48523, + "gen_feat_3": 504.39 + } + }, + { + "id": "t_dining_gen_97", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.51, + "time": 59.5, + "distance": 1634.44, + "gen_feat_1": 497.31, + "gen_feat_2": 0.5107, + "gen_feat_3": 507.86 + } + }, + { + "id": "t_dining_gen_98", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.5, + "time": 61.17, + "distance": 1593.89, + "gen_feat_1": 510.31, + "gen_feat_2": 0.50078, + "gen_feat_3": 494.95 + } + }, + { + "id": "t_shopping_gen_2", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.95, + "time": 44.3, + "distance": 1198.71, + "gen_feat_1": 508.4, + "gen_feat_2": 0.485625, + "gen_feat_3": 507.99 + } + }, + { + "id": "t_shopping_gen_3", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 44.18, + "distance": 1196.21, + "gen_feat_1": 485.72, + "gen_feat_2": 0.488455, + "gen_feat_3": 489.7 + } + }, + { + "id": "t_shopping_gen_4", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.78, + "time": 44.9, + "distance": 1179.12, + "gen_feat_1": 503.26, + "gen_feat_2": 0.498291, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_shopping_gen_5", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.51, + "time": 44.53, + "distance": 1216.23, + "gen_feat_1": 510.8, + "gen_feat_2": 0.507066, + "gen_feat_3": 504.03 + } + }, + { + "id": "t_shopping_gen_6", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.18, + "time": 44.06, + "distance": 1199.34, + "gen_feat_1": 501.17, + "gen_feat_2": 0.493458, + "gen_feat_3": 510.83 + } + }, + { + "id": "t_shopping_gen_7", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.59, + "time": 45.0, + "distance": 1183.14, + "gen_feat_1": 501.56, + "gen_feat_2": 0.496232, + "gen_feat_3": 496.33 + } + }, + { + "id": "t_shopping_gen_8", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.45, + "time": 43.75, + "distance": 1196.19, + "gen_feat_1": 488.54, + "gen_feat_2": 0.508864, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_9", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.29, + "time": 45.49, + "distance": 1235.6, + "gen_feat_1": 505.19, + "gen_feat_2": 0.486447, + "gen_feat_3": 505.3 + } + }, + { + "id": "t_shopping_gen_10", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.2, + "time": 44.86, + "distance": 1227.31, + "gen_feat_1": 487.19, + "gen_feat_2": 0.512416, + "gen_feat_3": 499.73 + } + }, + { + "id": "t_shopping_gen_11", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.86, + "time": 44.51, + "distance": 1227.77, + "gen_feat_1": 488.24, + "gen_feat_2": 0.510589, + "gen_feat_3": 510.74 + } + }, + { + "id": "t_shopping_gen_12", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.87, + "time": 44.69, + "distance": 1170.61, + "gen_feat_1": 503.79, + "gen_feat_2": 0.487994, + "gen_feat_3": 485.28 + } + }, + { + "id": "t_shopping_gen_13", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.87, + "time": 46.21, + "distance": 1228.85, + "gen_feat_1": 488.6, + "gen_feat_2": 0.499239, + "gen_feat_3": 503.2 + } + }, + { + "id": "t_shopping_gen_14", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.47, + "time": 44.09, + "distance": 1191.47, + "gen_feat_1": 510.69, + "gen_feat_2": 0.500607, + "gen_feat_3": 501.94 + } + }, + { + "id": "t_shopping_gen_15", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.91, + "time": 44.79, + "distance": 1194.44, + "gen_feat_1": 493.04, + "gen_feat_2": 0.493381, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_16", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.74, + "time": 45.76, + "distance": 1214.32, + "gen_feat_1": 508.04, + "gen_feat_2": 0.505849, + "gen_feat_3": 514.42 + } + }, + { + "id": "t_shopping_gen_17", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.56, + "time": 44.53, + "distance": 1186.46, + "gen_feat_1": 497.1, + "gen_feat_2": 0.507483, + "gen_feat_3": 487.33 + } + }, + { + "id": "t_shopping_gen_18", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.3, + "time": 46.02, + "distance": 1191.93, + "gen_feat_1": 502.5, + "gen_feat_2": 0.489832, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_shopping_gen_19", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.29, + "time": 44.76, + "distance": 1178.65, + "gen_feat_1": 486.31, + "gen_feat_2": 0.501927, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_shopping_gen_20", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.59, + "time": 45.62, + "distance": 1234.59, + "gen_feat_1": 508.23, + "gen_feat_2": 0.488622, + "gen_feat_3": 505.15 + } + }, + { + "id": "t_shopping_gen_21", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.41, + "time": 44.06, + "distance": 1185.1, + "gen_feat_1": 498.37, + "gen_feat_2": 0.491076, + "gen_feat_3": 502.07 + } + }, + { + "id": "t_shopping_gen_22", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.07, + "time": 45.23, + "distance": 1172.35, + "gen_feat_1": 489.15, + "gen_feat_2": 0.487341, + "gen_feat_3": 502.22 + } + }, + { + "id": "t_shopping_gen_23", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.07, + "time": 44.11, + "distance": 1228.63, + "gen_feat_1": 489.68, + "gen_feat_2": 0.497214, + "gen_feat_3": 510.3 + } + }, + { + "id": "t_shopping_gen_24", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.79, + "time": 45.29, + "distance": 1211.47, + "gen_feat_1": 513.99, + "gen_feat_2": 0.511272, + "gen_feat_3": 512.18 + } + }, + { + "id": "t_shopping_gen_25", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.49, + "time": 45.68, + "distance": 1197.16, + "gen_feat_1": 504.19, + "gen_feat_2": 0.507954, + "gen_feat_3": 509.7 + } + }, + { + "id": "t_shopping_gen_26", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.61, + "time": 45.73, + "distance": 1191.91, + "gen_feat_1": 499.13, + "gen_feat_2": 0.502797, + "gen_feat_3": 486.18 + } + }, + { + "id": "t_shopping_gen_27", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.64, + "time": 45.28, + "distance": 1176.71, + "gen_feat_1": 505.64, + "gen_feat_2": 0.491227, + "gen_feat_3": 508.35 + } + }, + { + "id": "t_shopping_gen_28", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.87, + "time": 45.0, + "distance": 1216.17, + "gen_feat_1": 500.61, + "gen_feat_2": 0.512609, + "gen_feat_3": 509.87 + } + }, + { + "id": "t_shopping_gen_29", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.37, + "time": 44.26, + "distance": 1180.24, + "gen_feat_1": 487.72, + "gen_feat_2": 0.485295, + "gen_feat_3": 487.2 + } + }, + { + "id": "t_shopping_gen_30", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.65, + "time": 44.57, + "distance": 1197.12, + "gen_feat_1": 500.2, + "gen_feat_2": 0.506494, + "gen_feat_3": 511.02 + } + }, + { + "id": "t_shopping_gen_31", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.54, + "time": 43.79, + "distance": 1190.28, + "gen_feat_1": 501.09, + "gen_feat_2": 0.496883, + "gen_feat_3": 504.0 + } + }, + { + "id": "t_shopping_gen_32", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.4, + "time": 44.15, + "distance": 1210.36, + "gen_feat_1": 506.65, + "gen_feat_2": 0.494619, + "gen_feat_3": 489.54 + } + }, + { + "id": "t_shopping_gen_33", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.78, + "time": 44.05, + "distance": 1224.7, + "gen_feat_1": 505.11, + "gen_feat_2": 0.497586, + "gen_feat_3": 502.56 + } + }, + { + "id": "t_shopping_gen_34", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.93, + "time": 45.15, + "distance": 1219.85, + "gen_feat_1": 498.34, + "gen_feat_2": 0.488983, + "gen_feat_3": 494.13 + } + }, + { + "id": "t_shopping_gen_35", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.82, + "time": 44.55, + "distance": 1224.73, + "gen_feat_1": 511.51, + "gen_feat_2": 0.504196, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_shopping_gen_36", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.86, + "time": 45.5, + "distance": 1196.08, + "gen_feat_1": 495.33, + "gen_feat_2": 0.498326, + "gen_feat_3": 486.34 + } + }, + { + "id": "t_shopping_gen_37", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.59, + "time": 44.26, + "distance": 1203.59, + "gen_feat_1": 496.81, + "gen_feat_2": 0.510331, + "gen_feat_3": 506.27 + } + }, + { + "id": "t_shopping_gen_38", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.92, + "time": 45.08, + "distance": 1203.94, + "gen_feat_1": 500.75, + "gen_feat_2": 0.49117, + "gen_feat_3": 491.78 + } + }, + { + "id": "t_shopping_gen_39", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.31, + "time": 46.16, + "distance": 1182.79, + "gen_feat_1": 497.1, + "gen_feat_2": 0.497946, + "gen_feat_3": 512.02 + } + }, + { + "id": "t_shopping_gen_40", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.54, + "time": 44.22, + "distance": 1217.58, + "gen_feat_1": 514.19, + "gen_feat_2": 0.507653, + "gen_feat_3": 502.34 + } + }, + { + "id": "t_shopping_gen_41", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.64, + "time": 44.32, + "distance": 1196.64, + "gen_feat_1": 510.6, + "gen_feat_2": 0.510227, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_42", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.93, + "time": 46.08, + "distance": 1215.22, + "gen_feat_1": 509.33, + "gen_feat_2": 0.489128, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_43", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.94, + "time": 46.06, + "distance": 1197.83, + "gen_feat_1": 494.23, + "gen_feat_2": 0.491429, + "gen_feat_3": 512.77 + } + }, + { + "id": "t_shopping_gen_44", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.62, + "time": 44.6, + "distance": 1228.92, + "gen_feat_1": 503.07, + "gen_feat_2": 0.497061, + "gen_feat_3": 508.73 + } + }, + { + "id": "t_shopping_gen_45", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.54, + "time": 45.8, + "distance": 1230.3, + "gen_feat_1": 498.44, + "gen_feat_2": 0.491182, + "gen_feat_3": 510.12 + } + }, + { + "id": "t_shopping_gen_46", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 44.28, + "distance": 1216.64, + "gen_feat_1": 488.95, + "gen_feat_2": 0.485686, + "gen_feat_3": 513.45 + } + }, + { + "id": "t_shopping_gen_47", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.4, + "time": 44.8, + "distance": 1210.54, + "gen_feat_1": 488.83, + "gen_feat_2": 0.508023, + "gen_feat_3": 485.22 + } + }, + { + "id": "t_shopping_gen_48", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.69, + "time": 44.94, + "distance": 1204.74, + "gen_feat_1": 504.02, + "gen_feat_2": 0.485166, + "gen_feat_3": 509.28 + } + }, + { + "id": "t_shopping_gen_49", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.63, + "time": 45.76, + "distance": 1234.29, + "gen_feat_1": 496.66, + "gen_feat_2": 0.510271, + "gen_feat_3": 488.57 + } + }, + { + "id": "t_shopping_gen_50", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.54, + "time": 44.91, + "distance": 1215.96, + "gen_feat_1": 509.77, + "gen_feat_2": 0.485673, + "gen_feat_3": 502.33 + } + }, + { + "id": "t_shopping_gen_51", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.48, + "time": 46.17, + "distance": 1186.08, + "gen_feat_1": 512.11, + "gen_feat_2": 0.491803, + "gen_feat_3": 503.47 + } + }, + { + "id": "t_shopping_gen_52", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.89, + "time": 44.45, + "distance": 1194.92, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486916, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_shopping_gen_53", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.35, + "time": 44.61, + "distance": 1191.25, + "gen_feat_1": 503.61, + "gen_feat_2": 0.493221, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_shopping_gen_54", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.73, + "time": 45.54, + "distance": 1223.55, + "gen_feat_1": 494.27, + "gen_feat_2": 0.490001, + "gen_feat_3": 493.72 + } + }, + { + "id": "t_shopping_gen_55", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 44.24, + "distance": 1228.06, + "gen_feat_1": 497.25, + "gen_feat_2": 0.49955, + "gen_feat_3": 486.14 + } + }, + { + "id": "t_shopping_gen_56", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.69, + "time": 44.04, + "distance": 1224.5, + "gen_feat_1": 492.29, + "gen_feat_2": 0.500032, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_57", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.68, + "time": 46.32, + "distance": 1227.05, + "gen_feat_1": 510.63, + "gen_feat_2": 0.51217, + "gen_feat_3": 489.8 + } + }, + { + "id": "t_shopping_gen_58", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.13, + "time": 45.42, + "distance": 1231.38, + "gen_feat_1": 499.25, + "gen_feat_2": 0.502657, + "gen_feat_3": 488.16 + } + }, + { + "id": "t_shopping_gen_59", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 45.04, + "distance": 1206.58, + "gen_feat_1": 488.66, + "gen_feat_2": 0.500622, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_shopping_gen_60", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.33, + "time": 46.0, + "distance": 1170.11, + "gen_feat_1": 511.4, + "gen_feat_2": 0.49549, + "gen_feat_3": 503.71 + } + }, + { + "id": "t_shopping_gen_61", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.18, + "time": 46.1, + "distance": 1190.97, + "gen_feat_1": 498.6, + "gen_feat_2": 0.501812, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_62", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.24, + "time": 45.7, + "distance": 1164.26, + "gen_feat_1": 485.26, + "gen_feat_2": 0.49031, + "gen_feat_3": 487.45 + } + }, + { + "id": "t_shopping_gen_63", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.17, + "time": 45.97, + "distance": 1190.2, + "gen_feat_1": 511.28, + "gen_feat_2": 0.51432, + "gen_feat_3": 513.58 + } + }, + { + "id": "t_shopping_gen_64", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.73, + "time": 44.03, + "distance": 1178.97, + "gen_feat_1": 487.49, + "gen_feat_2": 0.508632, + "gen_feat_3": 500.21 + } + }, + { + "id": "t_shopping_gen_65", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.67, + "time": 43.83, + "distance": 1176.27, + "gen_feat_1": 512.03, + "gen_feat_2": 0.49815, + "gen_feat_3": 501.03 + } + }, + { + "id": "t_shopping_gen_66", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.26, + "time": 44.73, + "distance": 1220.07, + "gen_feat_1": 504.64, + "gen_feat_2": 0.502789, + "gen_feat_3": 505.95 + } + }, + { + "id": "t_shopping_gen_67", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.81, + "time": 44.73, + "distance": 1180.99, + "gen_feat_1": 491.13, + "gen_feat_2": 0.488945, + "gen_feat_3": 487.4 + } + }, + { + "id": "t_shopping_gen_68", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.86, + "time": 43.67, + "distance": 1232.56, + "gen_feat_1": 512.67, + "gen_feat_2": 0.491258, + "gen_feat_3": 495.53 + } + }, + { + "id": "t_shopping_gen_69", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.0, + "time": 45.32, + "distance": 1179.79, + "gen_feat_1": 504.7, + "gen_feat_2": 0.501825, + "gen_feat_3": 494.35 + } + }, + { + "id": "t_shopping_gen_70", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 45.99, + "distance": 1206.39, + "gen_feat_1": 497.84, + "gen_feat_2": 0.509326, + "gen_feat_3": 508.37 + } + }, + { + "id": "t_shopping_gen_71", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.89, + "time": 44.23, + "distance": 1211.83, + "gen_feat_1": 489.02, + "gen_feat_2": 0.504569, + "gen_feat_3": 486.74 + } + }, + { + "id": "t_shopping_gen_72", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.25, + "time": 43.89, + "distance": 1218.83, + "gen_feat_1": 514.57, + "gen_feat_2": 0.487312, + "gen_feat_3": 491.96 + } + }, + { + "id": "t_shopping_gen_73", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 45.64, + "distance": 1171.76, + "gen_feat_1": 499.58, + "gen_feat_2": 0.499353, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_shopping_gen_74", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.51, + "time": 45.18, + "distance": 1235.16, + "gen_feat_1": 491.35, + "gen_feat_2": 0.488032, + "gen_feat_3": 508.76 + } + }, + { + "id": "t_shopping_gen_75", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.45, + "time": 45.29, + "distance": 1185.87, + "gen_feat_1": 506.16, + "gen_feat_2": 0.494622, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_shopping_gen_76", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.11, + "time": 44.39, + "distance": 1222.53, + "gen_feat_1": 507.53, + "gen_feat_2": 0.505002, + "gen_feat_3": 503.01 + } + }, + { + "id": "t_shopping_gen_77", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.93, + "time": 46.13, + "distance": 1210.75, + "gen_feat_1": 506.27, + "gen_feat_2": 0.505682, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_shopping_gen_78", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.16, + "time": 46.07, + "distance": 1210.7, + "gen_feat_1": 508.56, + "gen_feat_2": 0.487189, + "gen_feat_3": 504.12 + } + }, + { + "id": "t_shopping_gen_79", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.03, + "time": 45.66, + "distance": 1190.96, + "gen_feat_1": 489.72, + "gen_feat_2": 0.488214, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_shopping_gen_80", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.77, + "time": 45.73, + "distance": 1226.46, + "gen_feat_1": 498.85, + "gen_feat_2": 0.50612, + "gen_feat_3": 508.83 + } + }, + { + "id": "t_shopping_gen_81", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.19, + "time": 44.4, + "distance": 1207.41, + "gen_feat_1": 512.69, + "gen_feat_2": 0.49773, + "gen_feat_3": 499.57 + } + }, + { + "id": "t_shopping_gen_82", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.91, + "time": 45.81, + "distance": 1232.14, + "gen_feat_1": 501.37, + "gen_feat_2": 0.501413, + "gen_feat_3": 509.02 + } + }, + { + "id": "t_shopping_gen_83", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.46, + "time": 45.7, + "distance": 1201.06, + "gen_feat_1": 507.37, + "gen_feat_2": 0.512514, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_84", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.46, + "time": 45.7, + "distance": 1176.63, + "gen_feat_1": 500.57, + "gen_feat_2": 0.512907, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_shopping_gen_85", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.3, + "time": 44.77, + "distance": 1227.54, + "gen_feat_1": 488.72, + "gen_feat_2": 0.491267, + "gen_feat_3": 504.72 + } + }, + { + "id": "t_shopping_gen_86", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.53, + "time": 44.82, + "distance": 1227.19, + "gen_feat_1": 495.19, + "gen_feat_2": 0.506807, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_shopping_gen_87", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.76, + "time": 45.19, + "distance": 1197.27, + "gen_feat_1": 492.23, + "gen_feat_2": 0.502276, + "gen_feat_3": 497.83 + } + }, + { + "id": "t_shopping_gen_88", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.51, + "time": 46.32, + "distance": 1202.27, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500008, + "gen_feat_3": 494.37 + } + }, + { + "id": "t_shopping_gen_89", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.31, + "time": 45.09, + "distance": 1196.05, + "gen_feat_1": 488.52, + "gen_feat_2": 0.501783, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_90", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.15, + "time": 45.09, + "distance": 1187.36, + "gen_feat_1": 510.87, + "gen_feat_2": 0.48952, + "gen_feat_3": 487.44 + } + }, + { + "id": "t_shopping_gen_91", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.98, + "time": 44.28, + "distance": 1230.46, + "gen_feat_1": 494.85, + "gen_feat_2": 0.49072, + "gen_feat_3": 507.33 + } + }, + { + "id": "t_shopping_gen_92", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.46, + "time": 44.78, + "distance": 1190.65, + "gen_feat_1": 511.14, + "gen_feat_2": 0.491965, + "gen_feat_3": 510.07 + } + }, + { + "id": "t_shopping_gen_93", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 44.16, + "distance": 1232.76, + "gen_feat_1": 491.76, + "gen_feat_2": 0.49386, + "gen_feat_3": 489.99 + } + }, + { + "id": "t_shopping_gen_94", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.09, + "time": 45.07, + "distance": 1187.9, + "gen_feat_1": 500.36, + "gen_feat_2": 0.505173, + "gen_feat_3": 512.28 + } + }, + { + "id": "t_shopping_gen_95", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.29, + "time": 44.73, + "distance": 1224.17, + "gen_feat_1": 507.58, + "gen_feat_2": 0.48708, + "gen_feat_3": 511.59 + } + }, + { + "id": "t_shopping_gen_96", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.53, + "time": 43.89, + "distance": 1206.53, + "gen_feat_1": 493.71, + "gen_feat_2": 0.505153, + "gen_feat_3": 502.61 + } + }, + { + "id": "t_shopping_gen_97", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.6, + "time": 45.25, + "distance": 1198.77, + "gen_feat_1": 499.74, + "gen_feat_2": 0.499805, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_shopping_gen_98", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.94, + "time": 45.61, + "distance": 1168.51, + "gen_feat_1": 491.6, + "gen_feat_2": 0.511011, + "gen_feat_3": 491.45 + } + }, + { + "id": "t_shopping_gen_99", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.76, + "time": 45.99, + "distance": 1192.67, + "gen_feat_1": 500.07, + "gen_feat_2": 0.491787, + "gen_feat_3": 488.2 + } + }, + { + "id": "t_movie_gen_2", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.81, + "time": 138.02, + "distance": 1654.01, + "gen_feat_1": 503.91, + "gen_feat_2": 0.502664, + "gen_feat_3": 506.8 + } + }, + { + "id": "t_movie_gen_3", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.98, + "time": 133.32, + "distance": 1664.29, + "gen_feat_1": 491.47, + "gen_feat_2": 0.500325, + "gen_feat_3": 496.28 + } + }, + { + "id": "t_movie_gen_4", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.11, + "time": 136.06, + "distance": 1704.88, + "gen_feat_1": 505.19, + "gen_feat_2": 0.509953, + "gen_feat_3": 499.19 + } + }, + { + "id": "t_movie_gen_5", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.17, + "time": 136.4, + "distance": 1724.13, + "gen_feat_1": 511.77, + "gen_feat_2": 0.505076, + "gen_feat_3": 491.0 + } + }, + { + "id": "t_movie_gen_6", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.2, + "time": 137.15, + "distance": 1664.63, + "gen_feat_1": 514.48, + "gen_feat_2": 0.503771, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_movie_gen_7", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.16, + "time": 135.61, + "distance": 1726.58, + "gen_feat_1": 493.34, + "gen_feat_2": 0.493128, + "gen_feat_3": 491.4 + } + }, + { + "id": "t_movie_gen_8", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.91, + "time": 135.69, + "distance": 1678.5, + "gen_feat_1": 493.49, + "gen_feat_2": 0.506584, + "gen_feat_3": 491.95 + } + }, + { + "id": "t_movie_gen_9", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.09, + "time": 132.47, + "distance": 1682.74, + "gen_feat_1": 513.37, + "gen_feat_2": 0.496243, + "gen_feat_3": 510.52 + } + }, + { + "id": "t_movie_gen_10", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.25, + "time": 134.94, + "distance": 1683.72, + "gen_feat_1": 493.66, + "gen_feat_2": 0.502149, + "gen_feat_3": 491.38 + } + }, + { + "id": "t_movie_gen_11", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 132.2, + "distance": 1677.4, + "gen_feat_1": 513.51, + "gen_feat_2": 0.512663, + "gen_feat_3": 496.77 + } + }, + { + "id": "t_movie_gen_12", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.02, + "time": 136.12, + "distance": 1683.25, + "gen_feat_1": 486.72, + "gen_feat_2": 0.48763, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_movie_gen_13", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 131.91, + "distance": 1710.85, + "gen_feat_1": 493.33, + "gen_feat_2": 0.499006, + "gen_feat_3": 497.58 + } + }, + { + "id": "t_movie_gen_14", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.85, + "time": 137.69, + "distance": 1738.0, + "gen_feat_1": 501.65, + "gen_feat_2": 0.507629, + "gen_feat_3": 509.86 + } + }, + { + "id": "t_movie_gen_15", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.02, + "time": 133.61, + "distance": 1660.2, + "gen_feat_1": 512.64, + "gen_feat_2": 0.487548, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_movie_gen_16", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.2, + "time": 132.6, + "distance": 1669.36, + "gen_feat_1": 490.54, + "gen_feat_2": 0.507088, + "gen_feat_3": 496.37 + } + }, + { + "id": "t_movie_gen_17", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.25, + "time": 138.2, + "distance": 1711.42, + "gen_feat_1": 497.15, + "gen_feat_2": 0.513509, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_movie_gen_18", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.76, + "time": 136.31, + "distance": 1749.75, + "gen_feat_1": 514.83, + "gen_feat_2": 0.50335, + "gen_feat_3": 503.33 + } + }, + { + "id": "t_movie_gen_19", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 131.68, + "distance": 1656.52, + "gen_feat_1": 487.37, + "gen_feat_2": 0.493627, + "gen_feat_3": 508.19 + } + }, + { + "id": "t_movie_gen_20", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.9, + "time": 137.27, + "distance": 1709.53, + "gen_feat_1": 497.44, + "gen_feat_2": 0.486038, + "gen_feat_3": 502.32 + } + }, + { + "id": "t_movie_gen_21", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.83, + "time": 136.88, + "distance": 1708.94, + "gen_feat_1": 492.6, + "gen_feat_2": 0.496495, + "gen_feat_3": 490.83 + } + }, + { + "id": "t_movie_gen_22", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.12, + "time": 133.07, + "distance": 1711.62, + "gen_feat_1": 493.34, + "gen_feat_2": 0.499182, + "gen_feat_3": 499.28 + } + }, + { + "id": "t_movie_gen_23", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.12, + "time": 134.21, + "distance": 1736.25, + "gen_feat_1": 503.64, + "gen_feat_2": 0.5068, + "gen_feat_3": 489.21 + } + }, + { + "id": "t_movie_gen_24", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 132.64, + "distance": 1664.88, + "gen_feat_1": 510.09, + "gen_feat_2": 0.510289, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_movie_gen_25", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.1, + "time": 137.12, + "distance": 1701.34, + "gen_feat_1": 501.06, + "gen_feat_2": 0.49893, + "gen_feat_3": 507.73 + } + }, + { + "id": "t_movie_gen_26", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 136.45, + "distance": 1678.04, + "gen_feat_1": 494.8, + "gen_feat_2": 0.485118, + "gen_feat_3": 508.86 + } + }, + { + "id": "t_movie_gen_27", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.83, + "time": 134.67, + "distance": 1694.92, + "gen_feat_1": 503.64, + "gen_feat_2": 0.511029, + "gen_feat_3": 505.48 + } + }, + { + "id": "t_movie_gen_28", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.96, + "time": 138.62, + "distance": 1659.13, + "gen_feat_1": 491.47, + "gen_feat_2": 0.511429, + "gen_feat_3": 500.08 + } + }, + { + "id": "t_movie_gen_29", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.76, + "time": 138.64, + "distance": 1697.07, + "gen_feat_1": 498.44, + "gen_feat_2": 0.509025, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_movie_gen_30", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.39, + "distance": 1730.3, + "gen_feat_1": 510.02, + "gen_feat_2": 0.491101, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_31", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.28, + "time": 131.41, + "distance": 1685.65, + "gen_feat_1": 490.64, + "gen_feat_2": 0.485642, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_movie_gen_32", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.93, + "time": 134.98, + "distance": 1695.11, + "gen_feat_1": 501.21, + "gen_feat_2": 0.50543, + "gen_feat_3": 499.51 + } + }, + { + "id": "t_movie_gen_33", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.87, + "time": 137.83, + "distance": 1715.38, + "gen_feat_1": 513.71, + "gen_feat_2": 0.493568, + "gen_feat_3": 514.01 + } + }, + { + "id": "t_movie_gen_34", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.81, + "time": 132.4, + "distance": 1663.09, + "gen_feat_1": 506.91, + "gen_feat_2": 0.510638, + "gen_feat_3": 501.83 + } + }, + { + "id": "t_movie_gen_35", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.24, + "time": 136.79, + "distance": 1694.27, + "gen_feat_1": 510.84, + "gen_feat_2": 0.507452, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_movie_gen_36", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.16, + "time": 136.15, + "distance": 1670.24, + "gen_feat_1": 502.99, + "gen_feat_2": 0.495856, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_37", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.3, + "time": 136.48, + "distance": 1719.06, + "gen_feat_1": 512.77, + "gen_feat_2": 0.488773, + "gen_feat_3": 505.19 + } + }, + { + "id": "t_movie_gen_38", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.89, + "time": 137.8, + "distance": 1682.43, + "gen_feat_1": 514.67, + "gen_feat_2": 0.508214, + "gen_feat_3": 504.71 + } + }, + { + "id": "t_movie_gen_39", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.88, + "time": 136.94, + "distance": 1652.85, + "gen_feat_1": 499.19, + "gen_feat_2": 0.500729, + "gen_feat_3": 511.08 + } + }, + { + "id": "t_movie_gen_40", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.75, + "time": 136.81, + "distance": 1673.83, + "gen_feat_1": 510.5, + "gen_feat_2": 0.496266, + "gen_feat_3": 512.35 + } + }, + { + "id": "t_movie_gen_41", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.84, + "time": 133.13, + "distance": 1698.79, + "gen_feat_1": 504.79, + "gen_feat_2": 0.491761, + "gen_feat_3": 489.88 + } + }, + { + "id": "t_movie_gen_42", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.79, + "time": 132.71, + "distance": 1654.02, + "gen_feat_1": 488.54, + "gen_feat_2": 0.496646, + "gen_feat_3": 506.89 + } + }, + { + "id": "t_movie_gen_43", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.03, + "time": 135.73, + "distance": 1687.52, + "gen_feat_1": 489.12, + "gen_feat_2": 0.50799, + "gen_feat_3": 499.94 + } + }, + { + "id": "t_movie_gen_44", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.09, + "time": 138.68, + "distance": 1703.05, + "gen_feat_1": 510.12, + "gen_feat_2": 0.485551, + "gen_feat_3": 502.13 + } + }, + { + "id": "t_movie_gen_45", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.86, + "time": 133.42, + "distance": 1652.65, + "gen_feat_1": 488.6, + "gen_feat_2": 0.510397, + "gen_feat_3": 509.98 + } + }, + { + "id": "t_movie_gen_46", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.97, + "time": 131.94, + "distance": 1673.56, + "gen_feat_1": 486.56, + "gen_feat_2": 0.505523, + "gen_feat_3": 501.82 + } + }, + { + "id": "t_movie_gen_47", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.0, + "time": 133.55, + "distance": 1671.34, + "gen_feat_1": 488.32, + "gen_feat_2": 0.49915, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_movie_gen_48", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.06, + "time": 138.36, + "distance": 1677.66, + "gen_feat_1": 497.58, + "gen_feat_2": 0.497849, + "gen_feat_3": 488.29 + } + }, + { + "id": "t_movie_gen_49", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 133.95, + "distance": 1742.48, + "gen_feat_1": 495.5, + "gen_feat_2": 0.511503, + "gen_feat_3": 491.31 + } + }, + { + "id": "t_movie_gen_50", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.77, + "time": 135.54, + "distance": 1710.41, + "gen_feat_1": 487.97, + "gen_feat_2": 0.508317, + "gen_feat_3": 490.49 + } + }, + { + "id": "t_movie_gen_51", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.77, + "time": 135.9, + "distance": 1664.29, + "gen_feat_1": 513.14, + "gen_feat_2": 0.507714, + "gen_feat_3": 487.99 + } + }, + { + "id": "t_movie_gen_52", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.74, + "time": 133.36, + "distance": 1679.04, + "gen_feat_1": 502.14, + "gen_feat_2": 0.489374, + "gen_feat_3": 501.0 + } + }, + { + "id": "t_movie_gen_53", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.75, + "time": 137.75, + "distance": 1727.9, + "gen_feat_1": 494.43, + "gen_feat_2": 0.492795, + "gen_feat_3": 507.56 + } + }, + { + "id": "t_movie_gen_54", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 137.23, + "distance": 1749.88, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514964, + "gen_feat_3": 513.51 + } + }, + { + "id": "t_movie_gen_55", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.27, + "time": 131.7, + "distance": 1671.69, + "gen_feat_1": 491.71, + "gen_feat_2": 0.507637, + "gen_feat_3": 496.63 + } + }, + { + "id": "t_movie_gen_56", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.25, + "time": 133.82, + "distance": 1744.69, + "gen_feat_1": 513.96, + "gen_feat_2": 0.486719, + "gen_feat_3": 505.59 + } + }, + { + "id": "t_movie_gen_57", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.99, + "distance": 1687.02, + "gen_feat_1": 495.73, + "gen_feat_2": 0.497053, + "gen_feat_3": 485.08 + } + }, + { + "id": "t_movie_gen_58", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 134.0, + "distance": 1717.93, + "gen_feat_1": 498.58, + "gen_feat_2": 0.514512, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_movie_gen_59", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 135.99, + "distance": 1669.61, + "gen_feat_1": 506.91, + "gen_feat_2": 0.486343, + "gen_feat_3": 513.29 + } + }, + { + "id": "t_movie_gen_60", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 137.16, + "distance": 1727.65, + "gen_feat_1": 511.78, + "gen_feat_2": 0.498191, + "gen_feat_3": 495.09 + } + }, + { + "id": "t_movie_gen_61", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.06, + "time": 131.51, + "distance": 1688.72, + "gen_feat_1": 501.65, + "gen_feat_2": 0.503774, + "gen_feat_3": 494.98 + } + }, + { + "id": "t_movie_gen_62", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 134.94, + "distance": 1688.34, + "gen_feat_1": 486.17, + "gen_feat_2": 0.506252, + "gen_feat_3": 499.8 + } + }, + { + "id": "t_movie_gen_63", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.0, + "time": 132.52, + "distance": 1696.65, + "gen_feat_1": 514.69, + "gen_feat_2": 0.493209, + "gen_feat_3": 485.24 + } + }, + { + "id": "t_movie_gen_64", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.73, + "time": 131.33, + "distance": 1699.32, + "gen_feat_1": 494.73, + "gen_feat_2": 0.500638, + "gen_feat_3": 507.36 + } + }, + { + "id": "t_movie_gen_65", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.28, + "time": 135.57, + "distance": 1672.37, + "gen_feat_1": 512.61, + "gen_feat_2": 0.49003, + "gen_feat_3": 498.67 + } + }, + { + "id": "t_movie_gen_66", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.81, + "time": 133.8, + "distance": 1700.55, + "gen_feat_1": 512.0, + "gen_feat_2": 0.486179, + "gen_feat_3": 501.33 + } + }, + { + "id": "t_movie_gen_67", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.03, + "time": 131.77, + "distance": 1745.74, + "gen_feat_1": 503.3, + "gen_feat_2": 0.51441, + "gen_feat_3": 486.9 + } + }, + { + "id": "t_movie_gen_68", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.9, + "time": 137.31, + "distance": 1655.07, + "gen_feat_1": 485.6, + "gen_feat_2": 0.49856, + "gen_feat_3": 495.04 + } + }, + { + "id": "t_movie_gen_69", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.19, + "time": 137.9, + "distance": 1713.23, + "gen_feat_1": 510.23, + "gen_feat_2": 0.490473, + "gen_feat_3": 492.48 + } + }, + { + "id": "t_movie_gen_70", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.92, + "time": 137.74, + "distance": 1742.03, + "gen_feat_1": 497.94, + "gen_feat_2": 0.514756, + "gen_feat_3": 487.31 + } + }, + { + "id": "t_movie_gen_71", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.28, + "time": 134.06, + "distance": 1654.96, + "gen_feat_1": 510.56, + "gen_feat_2": 0.492021, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_movie_gen_72", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 135.82, + "distance": 1738.49, + "gen_feat_1": 500.42, + "gen_feat_2": 0.493135, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_73", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 134.69, + "distance": 1663.19, + "gen_feat_1": 491.2, + "gen_feat_2": 0.505794, + "gen_feat_3": 504.69 + } + }, + { + "id": "t_movie_gen_74", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.82, + "time": 132.56, + "distance": 1679.26, + "gen_feat_1": 497.39, + "gen_feat_2": 0.485217, + "gen_feat_3": 513.12 + } + }, + { + "id": "t_movie_gen_75", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.18, + "time": 134.95, + "distance": 1745.08, + "gen_feat_1": 491.08, + "gen_feat_2": 0.495277, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_movie_gen_76", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.16, + "time": 138.62, + "distance": 1666.98, + "gen_feat_1": 501.07, + "gen_feat_2": 0.506814, + "gen_feat_3": 489.44 + } + }, + { + "id": "t_movie_gen_77", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.76, + "time": 130.95, + "distance": 1675.39, + "gen_feat_1": 513.23, + "gen_feat_2": 0.496512, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_movie_gen_78", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.99, + "time": 132.12, + "distance": 1674.54, + "gen_feat_1": 495.99, + "gen_feat_2": 0.496439, + "gen_feat_3": 506.49 + } + }, + { + "id": "t_movie_gen_79", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.84, + "time": 132.9, + "distance": 1698.58, + "gen_feat_1": 486.83, + "gen_feat_2": 0.487385, + "gen_feat_3": 489.3 + } + }, + { + "id": "t_movie_gen_80", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 135.25, + "distance": 1703.48, + "gen_feat_1": 497.71, + "gen_feat_2": 0.506091, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_movie_gen_81", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.08, + "time": 138.34, + "distance": 1706.78, + "gen_feat_1": 501.18, + "gen_feat_2": 0.503416, + "gen_feat_3": 493.11 + } + }, + { + "id": "t_movie_gen_82", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.95, + "time": 132.28, + "distance": 1658.35, + "gen_feat_1": 488.13, + "gen_feat_2": 0.514958, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_83", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 135.04, + "distance": 1663.79, + "gen_feat_1": 495.07, + "gen_feat_2": 0.489223, + "gen_feat_3": 514.52 + } + }, + { + "id": "t_movie_gen_84", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.76, + "time": 137.41, + "distance": 1703.65, + "gen_feat_1": 504.9, + "gen_feat_2": 0.503529, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_movie_gen_85", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.08, + "time": 135.55, + "distance": 1691.79, + "gen_feat_1": 503.38, + "gen_feat_2": 0.5004, + "gen_feat_3": 510.63 + } + }, + { + "id": "t_movie_gen_86", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.24, + "time": 133.11, + "distance": 1689.53, + "gen_feat_1": 509.79, + "gen_feat_2": 0.49881, + "gen_feat_3": 488.86 + } + }, + { + "id": "t_movie_gen_87", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.89, + "time": 137.15, + "distance": 1698.06, + "gen_feat_1": 503.82, + "gen_feat_2": 0.50464, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_88", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.13, + "time": 131.18, + "distance": 1660.59, + "gen_feat_1": 492.85, + "gen_feat_2": 0.514114, + "gen_feat_3": 513.82 + } + }, + { + "id": "t_movie_gen_89", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.87, + "time": 135.02, + "distance": 1741.57, + "gen_feat_1": 501.92, + "gen_feat_2": 0.508398, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_90", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.28, + "time": 137.35, + "distance": 1718.09, + "gen_feat_1": 488.68, + "gen_feat_2": 0.49537, + "gen_feat_3": 493.95 + } + }, + { + "id": "t_movie_gen_91", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 137.3, + "distance": 1693.34, + "gen_feat_1": 493.19, + "gen_feat_2": 0.495672, + "gen_feat_3": 488.25 + } + }, + { + "id": "t_movie_gen_92", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.83, + "time": 137.58, + "distance": 1744.3, + "gen_feat_1": 491.56, + "gen_feat_2": 0.498387, + "gen_feat_3": 511.69 + } + }, + { + "id": "t_movie_gen_93", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.91, + "time": 133.34, + "distance": 1702.93, + "gen_feat_1": 488.01, + "gen_feat_2": 0.502779, + "gen_feat_3": 491.18 + } + }, + { + "id": "t_movie_gen_94", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 134.1, + "distance": 1680.7, + "gen_feat_1": 497.7, + "gen_feat_2": 0.497436, + "gen_feat_3": 502.47 + } + }, + { + "id": "t_movie_gen_95", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 136.67, + "distance": 1705.0, + "gen_feat_1": 488.28, + "gen_feat_2": 0.487878, + "gen_feat_3": 495.8 + } + }, + { + "id": "t_movie_gen_96", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.9, + "time": 134.07, + "distance": 1659.49, + "gen_feat_1": 492.47, + "gen_feat_2": 0.492451, + "gen_feat_3": 511.78 + } + }, + { + "id": "t_movie_gen_97", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.21, + "time": 134.31, + "distance": 1734.61, + "gen_feat_1": 493.2, + "gen_feat_2": 0.488477, + "gen_feat_3": 503.93 + } + }, + { + "id": "t_movie_gen_98", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 135.67, + "distance": 1729.26, + "gen_feat_1": 489.64, + "gen_feat_2": 0.491387, + "gen_feat_3": 506.86 + } + }, + { + "id": "t_movie_gen_99", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.79, + "time": 133.64, + "distance": 1673.71, + "gen_feat_1": 505.04, + "gen_feat_2": 0.505422, + "gen_feat_3": 513.37 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_dining", + "kind": "TASK", + "task_id": "t_dining" + }, + { + "id": "n_shopping", + "kind": "TASK", + "task_id": "t_shopping" + }, + { + "id": "n_movie", + "kind": "TASK", + "task_id": "t_movie" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "time": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "distance": { + "neutral": 0, + "compose": { + "seq": { + "fn": "MAX" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "c_within_2km", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "distance", + "op": "<=", + "value": 2000, + "hard": false + }, + { + "id": "c_time_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "time", + "op": "<=", + "value": 240, + "hard": false + }, + { + "id": "c_cost_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 100, + "hard": false + }, + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 50.07, + "hard": false + }, + { + "id": "gen_c_local_t_dining_time_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_dining" + ], + "attribute_id": "time", + "op": "<=", + "value": 59.79, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_dining", + "t_shopping" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_dining", + "t_movie" + ], + "hard": false + } + ], + "objective": { + "type": "MONO", + "targets": [ + "cost", + "distance", + "gen_feat_1", + "gen_feat_2", + "gen_feat_3", + "time" + ], + "weights": { + "cost": 0.17, + "distance": 0.17, + "gen_feat_1": 0.17, + "gen_feat_2": 0.17, + "gen_feat_3": 0.16, + "time": 0.16 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/zhang2014-entertainment-planner-running-example_multi_hard.json b/experimentation/instances/zhang2014-entertainment-planner-running-example_multi_hard.json new file mode 100644 index 0000000..4e87434 --- /dev/null +++ b/experimentation/instances/zhang2014-entertainment-planner-running-example_multi_hard.json @@ -0,0 +1,4534 @@ +{ + "metadata": { + "id": "zhang2014-entertainment-planner-running-example_multi_hard", + "name": "Personal Entertainment Planner (Zhang et al. 2014) [multi, hard]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:05Z", + "description": "Modeled from the motivating example in 'Context-aware Generic Service Discovery and Service Composition' (IEEE MobServ 2014).", + "paper": { + "title": "Context-aware Generic Service Discovery and Service Composition", + "authors": "Y. Zhang et al.", + "year": 2014, + "doi": "10.1109/MobServ.2014.27" + } + }, + "features": [ + { + "id": "cost", + "name": "Total money cost (USD)", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "time", + "name": "Total time cost (minutes)", + "direction": "MINIMIZE", + "unit": "min", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1440 + } + }, + { + "id": "distance", + "name": "Distance from user's current location (meters)", + "direction": "MINIMIZE", + "unit": "m", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 50000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_rest_autre_saison", + "name": "Restaurant L’Autre Saison" + }, + { + "id": "p_cinema_banque_scotia", + "name": "Cinema Banque Scotia Montreal" + }, + { + "id": "p_seven_night_club", + "name": "Seven Night Club" + }, + { + "id": "p_local_shopping", + "name": "Local Shopping (nearby venue)" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_dining", + "name": "Restaurant / Dining activity" + }, + { + "id": "t_shopping", + "name": "Shopping activity" + }, + { + "id": "t_movie", + "name": "Movie activity" + } + ], + "candidates": [ + { + "id": "c_dining_autre_saison", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison", + "features": { + "cost": 20, + "time": 60, + "distance": 1600, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_dining_seven_night_club", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Seven Night Club", + "features": { + "cost": 20, + "time": 60, + "distance": 1800, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopping_local", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue", + "features": { + "cost": 20, + "time": 45, + "distance": 1200, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_movie_the_help_banque_scotia", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal", + "features": { + "cost": 10, + "time": 135, + "distance": 1700, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_dining_gen_1", + "task_id": "t_dining", + "provider_id": "p_gen_shared", + "name": "Dinner at Restaurant L’Autre Saison (Gen Shared)", + "features": { + "cost": 20.2, + "time": 59.79, + "distance": 1570.05, + "gen_feat_1": 508.24, + "gen_feat_2": 0.514901, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_shopping_gen_1", + "task_id": "t_shopping", + "provider_id": "p_gen_shared", + "name": "Shopping at a nearby venue (Gen Shared)", + "features": { + "cost": 19.87, + "time": 44.98, + "distance": 1189.95, + "gen_feat_1": 485.24, + "gen_feat_2": 0.486287, + "gen_feat_3": 500.42 + } + }, + { + "id": "t_movie_gen_1", + "task_id": "t_movie", + "provider_id": "p_gen_shared", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen Shared)", + "features": { + "cost": 9.82, + "time": 134.28, + "distance": 1742.9, + "gen_feat_1": 512.03, + "gen_feat_2": 0.505972, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_dining_gen_2", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.53, + "time": 59.13, + "distance": 1559.02, + "gen_feat_1": 498.66, + "gen_feat_2": 0.488957, + "gen_feat_3": 503.61 + } + }, + { + "id": "t_dining_gen_3", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.94, + "time": 58.5, + "distance": 1591.09, + "gen_feat_1": 495.96, + "gen_feat_2": 0.504969, + "gen_feat_3": 506.77 + } + }, + { + "id": "t_dining_gen_4", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.8, + "time": 61.46, + "distance": 1629.91, + "gen_feat_1": 510.53, + "gen_feat_2": 0.508, + "gen_feat_3": 491.98 + } + }, + { + "id": "t_dining_gen_5", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.22, + "time": 60.39, + "distance": 1564.48, + "gen_feat_1": 491.41, + "gen_feat_2": 0.490673, + "gen_feat_3": 490.61 + } + }, + { + "id": "t_dining_gen_6", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.38, + "time": 58.67, + "distance": 1626.15, + "gen_feat_1": 488.5, + "gen_feat_2": 0.49348, + "gen_feat_3": 495.75 + } + }, + { + "id": "t_dining_gen_7", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.18, + "time": 60.72, + "distance": 1555.22, + "gen_feat_1": 505.8, + "gen_feat_2": 0.506719, + "gen_feat_3": 499.33 + } + }, + { + "id": "t_dining_gen_8", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.43, + "time": 59.64, + "distance": 1598.13, + "gen_feat_1": 503.89, + "gen_feat_2": 0.506945, + "gen_feat_3": 508.17 + } + }, + { + "id": "t_dining_gen_9", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.64, + "time": 60.54, + "distance": 1604.33, + "gen_feat_1": 486.84, + "gen_feat_2": 0.506628, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_dining_gen_10", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 60.17, + "distance": 1616.85, + "gen_feat_1": 507.44, + "gen_feat_2": 0.489997, + "gen_feat_3": 502.16 + } + }, + { + "id": "t_dining_gen_11", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.68, + "time": 59.16, + "distance": 1620.42, + "gen_feat_1": 507.98, + "gen_feat_2": 0.488942, + "gen_feat_3": 489.19 + } + }, + { + "id": "t_dining_gen_12", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.74, + "time": 59.04, + "distance": 1602.16, + "gen_feat_1": 504.58, + "gen_feat_2": 0.489389, + "gen_feat_3": 507.41 + } + }, + { + "id": "t_dining_gen_13", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.47, + "time": 58.89, + "distance": 1622.97, + "gen_feat_1": 492.31, + "gen_feat_2": 0.503154, + "gen_feat_3": 508.55 + } + }, + { + "id": "t_dining_gen_14", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.72, + "time": 58.91, + "distance": 1626.35, + "gen_feat_1": 509.41, + "gen_feat_2": 0.490291, + "gen_feat_3": 514.74 + } + }, + { + "id": "t_dining_gen_15", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.59, + "time": 60.67, + "distance": 1631.73, + "gen_feat_1": 493.43, + "gen_feat_2": 0.498961, + "gen_feat_3": 492.15 + } + }, + { + "id": "t_dining_gen_16", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.21, + "time": 59.57, + "distance": 1621.68, + "gen_feat_1": 502.04, + "gen_feat_2": 0.491944, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_dining_gen_17", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.33, + "time": 59.99, + "distance": 1602.82, + "gen_feat_1": 513.49, + "gen_feat_2": 0.510425, + "gen_feat_3": 506.46 + } + }, + { + "id": "t_dining_gen_18", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.02, + "time": 60.13, + "distance": 1639.2, + "gen_feat_1": 498.4, + "gen_feat_2": 0.499582, + "gen_feat_3": 504.62 + } + }, + { + "id": "t_dining_gen_19", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.03, + "time": 60.73, + "distance": 1642.13, + "gen_feat_1": 507.63, + "gen_feat_2": 0.500514, + "gen_feat_3": 495.73 + } + }, + { + "id": "t_dining_gen_20", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.33, + "time": 59.96, + "distance": 1568.96, + "gen_feat_1": 488.36, + "gen_feat_2": 0.514752, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_dining_gen_21", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.8, + "time": 58.42, + "distance": 1555.46, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486429, + "gen_feat_3": 488.41 + } + }, + { + "id": "t_dining_gen_22", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.66, + "time": 61.62, + "distance": 1580.67, + "gen_feat_1": 491.06, + "gen_feat_2": 0.506184, + "gen_feat_3": 501.23 + } + }, + { + "id": "t_dining_gen_23", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.42, + "time": 61.78, + "distance": 1622.72, + "gen_feat_1": 490.83, + "gen_feat_2": 0.489949, + "gen_feat_3": 487.73 + } + }, + { + "id": "t_dining_gen_24", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.71, + "time": 59.51, + "distance": 1580.85, + "gen_feat_1": 501.15, + "gen_feat_2": 0.50297, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_25", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.42, + "time": 61.41, + "distance": 1578.66, + "gen_feat_1": 507.39, + "gen_feat_2": 0.499268, + "gen_feat_3": 490.28 + } + }, + { + "id": "t_dining_gen_26", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.55, + "time": 58.26, + "distance": 1560.85, + "gen_feat_1": 492.17, + "gen_feat_2": 0.492399, + "gen_feat_3": 511.94 + } + }, + { + "id": "t_dining_gen_27", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.48, + "time": 58.34, + "distance": 1631.2, + "gen_feat_1": 498.39, + "gen_feat_2": 0.490821, + "gen_feat_3": 491.03 + } + }, + { + "id": "t_dining_gen_28", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.04, + "time": 61.28, + "distance": 1606.8, + "gen_feat_1": 512.73, + "gen_feat_2": 0.509267, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_dining_gen_29", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.76, + "time": 60.3, + "distance": 1569.61, + "gen_feat_1": 490.22, + "gen_feat_2": 0.496831, + "gen_feat_3": 496.53 + } + }, + { + "id": "t_dining_gen_30", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.71, + "time": 60.3, + "distance": 1623.3, + "gen_feat_1": 500.21, + "gen_feat_2": 0.496569, + "gen_feat_3": 498.99 + } + }, + { + "id": "t_dining_gen_31", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.86, + "time": 59.05, + "distance": 1588.58, + "gen_feat_1": 485.96, + "gen_feat_2": 0.512749, + "gen_feat_3": 498.55 + } + }, + { + "id": "t_dining_gen_32", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.8, + "time": 59.8, + "distance": 1560.3, + "gen_feat_1": 512.24, + "gen_feat_2": 0.486102, + "gen_feat_3": 508.8 + } + }, + { + "id": "t_dining_gen_33", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.49, + "time": 61.12, + "distance": 1612.82, + "gen_feat_1": 506.05, + "gen_feat_2": 0.504153, + "gen_feat_3": 510.28 + } + }, + { + "id": "t_dining_gen_34", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.66, + "time": 58.74, + "distance": 1627.51, + "gen_feat_1": 494.47, + "gen_feat_2": 0.509322, + "gen_feat_3": 485.53 + } + }, + { + "id": "t_dining_gen_35", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.14, + "time": 60.57, + "distance": 1626.08, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513739, + "gen_feat_3": 510.69 + } + }, + { + "id": "t_dining_gen_36", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.57, + "time": 58.38, + "distance": 1610.88, + "gen_feat_1": 495.23, + "gen_feat_2": 0.509726, + "gen_feat_3": 512.08 + } + }, + { + "id": "t_dining_gen_37", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.41, + "distance": 1575.46, + "gen_feat_1": 512.15, + "gen_feat_2": 0.492042, + "gen_feat_3": 505.13 + } + }, + { + "id": "t_dining_gen_38", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.22, + "time": 59.29, + "distance": 1557.64, + "gen_feat_1": 489.83, + "gen_feat_2": 0.49146, + "gen_feat_3": 495.3 + } + }, + { + "id": "t_dining_gen_39", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.59, + "time": 61.53, + "distance": 1562.65, + "gen_feat_1": 495.8, + "gen_feat_2": 0.496923, + "gen_feat_3": 507.91 + } + }, + { + "id": "t_dining_gen_40", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.43, + "time": 60.01, + "distance": 1604.0, + "gen_feat_1": 500.49, + "gen_feat_2": 0.514685, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_41", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.58, + "time": 60.72, + "distance": 1645.52, + "gen_feat_1": 487.19, + "gen_feat_2": 0.508959, + "gen_feat_3": 497.39 + } + }, + { + "id": "t_dining_gen_42", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.2, + "time": 59.26, + "distance": 1581.92, + "gen_feat_1": 509.7, + "gen_feat_2": 0.513201, + "gen_feat_3": 491.13 + } + }, + { + "id": "t_dining_gen_43", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.45, + "time": 60.26, + "distance": 1568.18, + "gen_feat_1": 493.86, + "gen_feat_2": 0.514555, + "gen_feat_3": 489.48 + } + }, + { + "id": "t_dining_gen_44", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.58, + "time": 58.5, + "distance": 1617.8, + "gen_feat_1": 491.08, + "gen_feat_2": 0.513671, + "gen_feat_3": 486.88 + } + }, + { + "id": "t_dining_gen_45", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.68, + "time": 61.23, + "distance": 1579.97, + "gen_feat_1": 509.82, + "gen_feat_2": 0.504088, + "gen_feat_3": 512.95 + } + }, + { + "id": "t_dining_gen_46", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 60.56, + "distance": 1641.45, + "gen_feat_1": 499.89, + "gen_feat_2": 0.510488, + "gen_feat_3": 491.3 + } + }, + { + "id": "t_dining_gen_47", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.94, + "time": 58.84, + "distance": 1629.37, + "gen_feat_1": 494.2, + "gen_feat_2": 0.49711, + "gen_feat_3": 496.8 + } + }, + { + "id": "t_dining_gen_48", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.23, + "time": 58.97, + "distance": 1607.14, + "gen_feat_1": 485.39, + "gen_feat_2": 0.485086, + "gen_feat_3": 504.57 + } + }, + { + "id": "t_dining_gen_49", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.47, + "time": 59.57, + "distance": 1615.57, + "gen_feat_1": 495.03, + "gen_feat_2": 0.503496, + "gen_feat_3": 509.51 + } + }, + { + "id": "t_dining_gen_50", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.7, + "distance": 1583.69, + "gen_feat_1": 489.31, + "gen_feat_2": 0.498993, + "gen_feat_3": 498.25 + } + }, + { + "id": "t_dining_gen_51", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.06, + "time": 60.11, + "distance": 1630.7, + "gen_feat_1": 507.83, + "gen_feat_2": 0.497927, + "gen_feat_3": 485.62 + } + }, + { + "id": "t_dining_gen_52", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.53, + "time": 58.59, + "distance": 1646.13, + "gen_feat_1": 489.54, + "gen_feat_2": 0.503777, + "gen_feat_3": 487.65 + } + }, + { + "id": "t_dining_gen_53", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.9, + "time": 58.5, + "distance": 1634.44, + "gen_feat_1": 514.43, + "gen_feat_2": 0.508093, + "gen_feat_3": 499.44 + } + }, + { + "id": "t_dining_gen_54", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.18, + "time": 58.68, + "distance": 1576.83, + "gen_feat_1": 491.93, + "gen_feat_2": 0.485409, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_dining_gen_55", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.0, + "distance": 1581.79, + "gen_feat_1": 489.92, + "gen_feat_2": 0.49016, + "gen_feat_3": 513.4 + } + }, + { + "id": "t_dining_gen_56", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.18, + "time": 61.73, + "distance": 1637.68, + "gen_feat_1": 492.48, + "gen_feat_2": 0.497966, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_dining_gen_57", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.2, + "time": 61.78, + "distance": 1646.08, + "gen_feat_1": 508.92, + "gen_feat_2": 0.500426, + "gen_feat_3": 499.7 + } + }, + { + "id": "t_dining_gen_58", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.57, + "time": 59.32, + "distance": 1580.58, + "gen_feat_1": 509.74, + "gen_feat_2": 0.510379, + "gen_feat_3": 512.86 + } + }, + { + "id": "t_dining_gen_59", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.54, + "time": 59.3, + "distance": 1570.05, + "gen_feat_1": 486.4, + "gen_feat_2": 0.503502, + "gen_feat_3": 498.65 + } + }, + { + "id": "t_dining_gen_60", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.18, + "time": 61.43, + "distance": 1636.11, + "gen_feat_1": 485.66, + "gen_feat_2": 0.498532, + "gen_feat_3": 506.32 + } + }, + { + "id": "t_dining_gen_61", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.01, + "time": 59.61, + "distance": 1626.73, + "gen_feat_1": 507.2, + "gen_feat_2": 0.505098, + "gen_feat_3": 499.85 + } + }, + { + "id": "t_dining_gen_62", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.22, + "time": 59.78, + "distance": 1646.36, + "gen_feat_1": 500.64, + "gen_feat_2": 0.500049, + "gen_feat_3": 504.88 + } + }, + { + "id": "t_dining_gen_63", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.11, + "time": 59.7, + "distance": 1621.52, + "gen_feat_1": 494.18, + "gen_feat_2": 0.498313, + "gen_feat_3": 506.17 + } + }, + { + "id": "t_dining_gen_64", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.71, + "time": 61.36, + "distance": 1568.12, + "gen_feat_1": 493.75, + "gen_feat_2": 0.505406, + "gen_feat_3": 512.82 + } + }, + { + "id": "t_dining_gen_65", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.4, + "time": 58.28, + "distance": 1604.89, + "gen_feat_1": 487.06, + "gen_feat_2": 0.502445, + "gen_feat_3": 511.12 + } + }, + { + "id": "t_dining_gen_66", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 59.57, + "distance": 1581.66, + "gen_feat_1": 513.25, + "gen_feat_2": 0.493068, + "gen_feat_3": 505.54 + } + }, + { + "id": "t_dining_gen_67", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.21, + "time": 60.81, + "distance": 1606.42, + "gen_feat_1": 493.36, + "gen_feat_2": 0.50459, + "gen_feat_3": 493.01 + } + }, + { + "id": "t_dining_gen_68", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 59.09, + "distance": 1611.43, + "gen_feat_1": 505.83, + "gen_feat_2": 0.502644, + "gen_feat_3": 504.4 + } + }, + { + "id": "t_dining_gen_69", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.92, + "time": 61.04, + "distance": 1579.9, + "gen_feat_1": 512.7, + "gen_feat_2": 0.488813, + "gen_feat_3": 500.85 + } + }, + { + "id": "t_dining_gen_70", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.74, + "time": 59.83, + "distance": 1615.86, + "gen_feat_1": 505.67, + "gen_feat_2": 0.48967, + "gen_feat_3": 503.59 + } + }, + { + "id": "t_dining_gen_71", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 61.74, + "distance": 1585.25, + "gen_feat_1": 495.74, + "gen_feat_2": 0.490106, + "gen_feat_3": 499.93 + } + }, + { + "id": "t_dining_gen_72", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.9, + "time": 58.61, + "distance": 1604.96, + "gen_feat_1": 509.49, + "gen_feat_2": 0.512456, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_73", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.41, + "time": 59.23, + "distance": 1631.69, + "gen_feat_1": 507.39, + "gen_feat_2": 0.504155, + "gen_feat_3": 514.37 + } + }, + { + "id": "t_dining_gen_74", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.5, + "time": 58.7, + "distance": 1628.56, + "gen_feat_1": 514.96, + "gen_feat_2": 0.498875, + "gen_feat_3": 512.16 + } + }, + { + "id": "t_dining_gen_75", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.83, + "time": 61.78, + "distance": 1589.19, + "gen_feat_1": 501.13, + "gen_feat_2": 0.504679, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_dining_gen_76", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.02, + "time": 61.78, + "distance": 1596.36, + "gen_feat_1": 511.57, + "gen_feat_2": 0.51185, + "gen_feat_3": 493.99 + } + }, + { + "id": "t_dining_gen_77", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.38, + "time": 59.52, + "distance": 1573.49, + "gen_feat_1": 513.61, + "gen_feat_2": 0.50886, + "gen_feat_3": 505.08 + } + }, + { + "id": "t_dining_gen_78", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.28, + "time": 59.03, + "distance": 1628.26, + "gen_feat_1": 513.77, + "gen_feat_2": 0.508209, + "gen_feat_3": 504.63 + } + }, + { + "id": "t_dining_gen_79", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.75, + "time": 60.98, + "distance": 1603.39, + "gen_feat_1": 510.74, + "gen_feat_2": 0.51442, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_dining_gen_80", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.34, + "time": 59.39, + "distance": 1607.15, + "gen_feat_1": 489.01, + "gen_feat_2": 0.508841, + "gen_feat_3": 503.65 + } + }, + { + "id": "t_dining_gen_81", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.78, + "time": 61.32, + "distance": 1606.79, + "gen_feat_1": 494.77, + "gen_feat_2": 0.498081, + "gen_feat_3": 490.68 + } + }, + { + "id": "t_dining_gen_82", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.0, + "time": 60.47, + "distance": 1578.03, + "gen_feat_1": 505.85, + "gen_feat_2": 0.496498, + "gen_feat_3": 494.3 + } + }, + { + "id": "t_dining_gen_83", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.59, + "time": 60.4, + "distance": 1576.41, + "gen_feat_1": 487.54, + "gen_feat_2": 0.490813, + "gen_feat_3": 506.97 + } + }, + { + "id": "t_dining_gen_84", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.45, + "time": 58.59, + "distance": 1635.41, + "gen_feat_1": 507.53, + "gen_feat_2": 0.499359, + "gen_feat_3": 511.49 + } + }, + { + "id": "t_dining_gen_85", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.55, + "time": 59.37, + "distance": 1578.95, + "gen_feat_1": 500.14, + "gen_feat_2": 0.504331, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_dining_gen_86", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.11, + "distance": 1556.1, + "gen_feat_1": 513.36, + "gen_feat_2": 0.512958, + "gen_feat_3": 493.44 + } + }, + { + "id": "t_dining_gen_87", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.26, + "time": 59.23, + "distance": 1563.62, + "gen_feat_1": 489.36, + "gen_feat_2": 0.51222, + "gen_feat_3": 503.86 + } + }, + { + "id": "t_dining_gen_88", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.46, + "time": 61.2, + "distance": 1588.14, + "gen_feat_1": 488.89, + "gen_feat_2": 0.496175, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_dining_gen_89", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.79, + "time": 58.63, + "distance": 1622.85, + "gen_feat_1": 512.62, + "gen_feat_2": 0.485995, + "gen_feat_3": 487.83 + } + }, + { + "id": "t_dining_gen_90", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.48, + "time": 58.69, + "distance": 1640.49, + "gen_feat_1": 511.37, + "gen_feat_2": 0.494218, + "gen_feat_3": 505.83 + } + }, + { + "id": "t_dining_gen_91", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.58, + "time": 58.72, + "distance": 1630.9, + "gen_feat_1": 505.33, + "gen_feat_2": 0.485446, + "gen_feat_3": 496.64 + } + }, + { + "id": "t_dining_gen_92", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.04, + "time": 59.56, + "distance": 1559.07, + "gen_feat_1": 491.21, + "gen_feat_2": 0.509726, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_93", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.84, + "time": 60.45, + "distance": 1596.68, + "gen_feat_1": 493.98, + "gen_feat_2": 0.489239, + "gen_feat_3": 493.56 + } + }, + { + "id": "t_dining_gen_94", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.56, + "time": 59.95, + "distance": 1630.28, + "gen_feat_1": 488.49, + "gen_feat_2": 0.505218, + "gen_feat_3": 491.42 + } + }, + { + "id": "t_dining_gen_95", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.97, + "time": 59.51, + "distance": 1593.3, + "gen_feat_1": 488.66, + "gen_feat_2": 0.490214, + "gen_feat_3": 504.25 + } + }, + { + "id": "t_dining_gen_96", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.85, + "time": 58.35, + "distance": 1552.26, + "gen_feat_1": 503.49, + "gen_feat_2": 0.48523, + "gen_feat_3": 504.39 + } + }, + { + "id": "t_dining_gen_97", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.51, + "time": 59.5, + "distance": 1634.44, + "gen_feat_1": 497.31, + "gen_feat_2": 0.5107, + "gen_feat_3": 507.86 + } + }, + { + "id": "t_dining_gen_98", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.5, + "time": 61.17, + "distance": 1593.89, + "gen_feat_1": 510.31, + "gen_feat_2": 0.50078, + "gen_feat_3": 494.95 + } + }, + { + "id": "t_shopping_gen_2", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.95, + "time": 44.3, + "distance": 1198.71, + "gen_feat_1": 508.4, + "gen_feat_2": 0.485625, + "gen_feat_3": 507.99 + } + }, + { + "id": "t_shopping_gen_3", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 44.18, + "distance": 1196.21, + "gen_feat_1": 485.72, + "gen_feat_2": 0.488455, + "gen_feat_3": 489.7 + } + }, + { + "id": "t_shopping_gen_4", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.78, + "time": 44.9, + "distance": 1179.12, + "gen_feat_1": 503.26, + "gen_feat_2": 0.498291, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_shopping_gen_5", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.51, + "time": 44.53, + "distance": 1216.23, + "gen_feat_1": 510.8, + "gen_feat_2": 0.507066, + "gen_feat_3": 504.03 + } + }, + { + "id": "t_shopping_gen_6", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.18, + "time": 44.06, + "distance": 1199.34, + "gen_feat_1": 501.17, + "gen_feat_2": 0.493458, + "gen_feat_3": 510.83 + } + }, + { + "id": "t_shopping_gen_7", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.59, + "time": 45.0, + "distance": 1183.14, + "gen_feat_1": 501.56, + "gen_feat_2": 0.496232, + "gen_feat_3": 496.33 + } + }, + { + "id": "t_shopping_gen_8", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.45, + "time": 43.75, + "distance": 1196.19, + "gen_feat_1": 488.54, + "gen_feat_2": 0.508864, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_9", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.29, + "time": 45.49, + "distance": 1235.6, + "gen_feat_1": 505.19, + "gen_feat_2": 0.486447, + "gen_feat_3": 505.3 + } + }, + { + "id": "t_shopping_gen_10", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.2, + "time": 44.86, + "distance": 1227.31, + "gen_feat_1": 487.19, + "gen_feat_2": 0.512416, + "gen_feat_3": 499.73 + } + }, + { + "id": "t_shopping_gen_11", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.86, + "time": 44.51, + "distance": 1227.77, + "gen_feat_1": 488.24, + "gen_feat_2": 0.510589, + "gen_feat_3": 510.74 + } + }, + { + "id": "t_shopping_gen_12", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.87, + "time": 44.69, + "distance": 1170.61, + "gen_feat_1": 503.79, + "gen_feat_2": 0.487994, + "gen_feat_3": 485.28 + } + }, + { + "id": "t_shopping_gen_13", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.87, + "time": 46.21, + "distance": 1228.85, + "gen_feat_1": 488.6, + "gen_feat_2": 0.499239, + "gen_feat_3": 503.2 + } + }, + { + "id": "t_shopping_gen_14", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.47, + "time": 44.09, + "distance": 1191.47, + "gen_feat_1": 510.69, + "gen_feat_2": 0.500607, + "gen_feat_3": 501.94 + } + }, + { + "id": "t_shopping_gen_15", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.91, + "time": 44.79, + "distance": 1194.44, + "gen_feat_1": 493.04, + "gen_feat_2": 0.493381, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_16", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.74, + "time": 45.76, + "distance": 1214.32, + "gen_feat_1": 508.04, + "gen_feat_2": 0.505849, + "gen_feat_3": 514.42 + } + }, + { + "id": "t_shopping_gen_17", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.56, + "time": 44.53, + "distance": 1186.46, + "gen_feat_1": 497.1, + "gen_feat_2": 0.507483, + "gen_feat_3": 487.33 + } + }, + { + "id": "t_shopping_gen_18", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.3, + "time": 46.02, + "distance": 1191.93, + "gen_feat_1": 502.5, + "gen_feat_2": 0.489832, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_shopping_gen_19", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.29, + "time": 44.76, + "distance": 1178.65, + "gen_feat_1": 486.31, + "gen_feat_2": 0.501927, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_shopping_gen_20", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.59, + "time": 45.62, + "distance": 1234.59, + "gen_feat_1": 508.23, + "gen_feat_2": 0.488622, + "gen_feat_3": 505.15 + } + }, + { + "id": "t_shopping_gen_21", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.41, + "time": 44.06, + "distance": 1185.1, + "gen_feat_1": 498.37, + "gen_feat_2": 0.491076, + "gen_feat_3": 502.07 + } + }, + { + "id": "t_shopping_gen_22", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.07, + "time": 45.23, + "distance": 1172.35, + "gen_feat_1": 489.15, + "gen_feat_2": 0.487341, + "gen_feat_3": 502.22 + } + }, + { + "id": "t_shopping_gen_23", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.07, + "time": 44.11, + "distance": 1228.63, + "gen_feat_1": 489.68, + "gen_feat_2": 0.497214, + "gen_feat_3": 510.3 + } + }, + { + "id": "t_shopping_gen_24", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.79, + "time": 45.29, + "distance": 1211.47, + "gen_feat_1": 513.99, + "gen_feat_2": 0.511272, + "gen_feat_3": 512.18 + } + }, + { + "id": "t_shopping_gen_25", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.49, + "time": 45.68, + "distance": 1197.16, + "gen_feat_1": 504.19, + "gen_feat_2": 0.507954, + "gen_feat_3": 509.7 + } + }, + { + "id": "t_shopping_gen_26", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.61, + "time": 45.73, + "distance": 1191.91, + "gen_feat_1": 499.13, + "gen_feat_2": 0.502797, + "gen_feat_3": 486.18 + } + }, + { + "id": "t_shopping_gen_27", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.64, + "time": 45.28, + "distance": 1176.71, + "gen_feat_1": 505.64, + "gen_feat_2": 0.491227, + "gen_feat_3": 508.35 + } + }, + { + "id": "t_shopping_gen_28", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.87, + "time": 45.0, + "distance": 1216.17, + "gen_feat_1": 500.61, + "gen_feat_2": 0.512609, + "gen_feat_3": 509.87 + } + }, + { + "id": "t_shopping_gen_29", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.37, + "time": 44.26, + "distance": 1180.24, + "gen_feat_1": 487.72, + "gen_feat_2": 0.485295, + "gen_feat_3": 487.2 + } + }, + { + "id": "t_shopping_gen_30", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.65, + "time": 44.57, + "distance": 1197.12, + "gen_feat_1": 500.2, + "gen_feat_2": 0.506494, + "gen_feat_3": 511.02 + } + }, + { + "id": "t_shopping_gen_31", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.54, + "time": 43.79, + "distance": 1190.28, + "gen_feat_1": 501.09, + "gen_feat_2": 0.496883, + "gen_feat_3": 504.0 + } + }, + { + "id": "t_shopping_gen_32", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.4, + "time": 44.15, + "distance": 1210.36, + "gen_feat_1": 506.65, + "gen_feat_2": 0.494619, + "gen_feat_3": 489.54 + } + }, + { + "id": "t_shopping_gen_33", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.78, + "time": 44.05, + "distance": 1224.7, + "gen_feat_1": 505.11, + "gen_feat_2": 0.497586, + "gen_feat_3": 502.56 + } + }, + { + "id": "t_shopping_gen_34", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.93, + "time": 45.15, + "distance": 1219.85, + "gen_feat_1": 498.34, + "gen_feat_2": 0.488983, + "gen_feat_3": 494.13 + } + }, + { + "id": "t_shopping_gen_35", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.82, + "time": 44.55, + "distance": 1224.73, + "gen_feat_1": 511.51, + "gen_feat_2": 0.504196, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_shopping_gen_36", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.86, + "time": 45.5, + "distance": 1196.08, + "gen_feat_1": 495.33, + "gen_feat_2": 0.498326, + "gen_feat_3": 486.34 + } + }, + { + "id": "t_shopping_gen_37", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.59, + "time": 44.26, + "distance": 1203.59, + "gen_feat_1": 496.81, + "gen_feat_2": 0.510331, + "gen_feat_3": 506.27 + } + }, + { + "id": "t_shopping_gen_38", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.92, + "time": 45.08, + "distance": 1203.94, + "gen_feat_1": 500.75, + "gen_feat_2": 0.49117, + "gen_feat_3": 491.78 + } + }, + { + "id": "t_shopping_gen_39", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.31, + "time": 46.16, + "distance": 1182.79, + "gen_feat_1": 497.1, + "gen_feat_2": 0.497946, + "gen_feat_3": 512.02 + } + }, + { + "id": "t_shopping_gen_40", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.54, + "time": 44.22, + "distance": 1217.58, + "gen_feat_1": 514.19, + "gen_feat_2": 0.507653, + "gen_feat_3": 502.34 + } + }, + { + "id": "t_shopping_gen_41", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.64, + "time": 44.32, + "distance": 1196.64, + "gen_feat_1": 510.6, + "gen_feat_2": 0.510227, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_42", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.93, + "time": 46.08, + "distance": 1215.22, + "gen_feat_1": 509.33, + "gen_feat_2": 0.489128, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_43", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.94, + "time": 46.06, + "distance": 1197.83, + "gen_feat_1": 494.23, + "gen_feat_2": 0.491429, + "gen_feat_3": 512.77 + } + }, + { + "id": "t_shopping_gen_44", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.62, + "time": 44.6, + "distance": 1228.92, + "gen_feat_1": 503.07, + "gen_feat_2": 0.497061, + "gen_feat_3": 508.73 + } + }, + { + "id": "t_shopping_gen_45", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.54, + "time": 45.8, + "distance": 1230.3, + "gen_feat_1": 498.44, + "gen_feat_2": 0.491182, + "gen_feat_3": 510.12 + } + }, + { + "id": "t_shopping_gen_46", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 44.28, + "distance": 1216.64, + "gen_feat_1": 488.95, + "gen_feat_2": 0.485686, + "gen_feat_3": 513.45 + } + }, + { + "id": "t_shopping_gen_47", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.4, + "time": 44.8, + "distance": 1210.54, + "gen_feat_1": 488.83, + "gen_feat_2": 0.508023, + "gen_feat_3": 485.22 + } + }, + { + "id": "t_shopping_gen_48", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.69, + "time": 44.94, + "distance": 1204.74, + "gen_feat_1": 504.02, + "gen_feat_2": 0.485166, + "gen_feat_3": 509.28 + } + }, + { + "id": "t_shopping_gen_49", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.63, + "time": 45.76, + "distance": 1234.29, + "gen_feat_1": 496.66, + "gen_feat_2": 0.510271, + "gen_feat_3": 488.57 + } + }, + { + "id": "t_shopping_gen_50", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.54, + "time": 44.91, + "distance": 1215.96, + "gen_feat_1": 509.77, + "gen_feat_2": 0.485673, + "gen_feat_3": 502.33 + } + }, + { + "id": "t_shopping_gen_51", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.48, + "time": 46.17, + "distance": 1186.08, + "gen_feat_1": 512.11, + "gen_feat_2": 0.491803, + "gen_feat_3": 503.47 + } + }, + { + "id": "t_shopping_gen_52", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.89, + "time": 44.45, + "distance": 1194.92, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486916, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_shopping_gen_53", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.35, + "time": 44.61, + "distance": 1191.25, + "gen_feat_1": 503.61, + "gen_feat_2": 0.493221, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_shopping_gen_54", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.73, + "time": 45.54, + "distance": 1223.55, + "gen_feat_1": 494.27, + "gen_feat_2": 0.490001, + "gen_feat_3": 493.72 + } + }, + { + "id": "t_shopping_gen_55", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 44.24, + "distance": 1228.06, + "gen_feat_1": 497.25, + "gen_feat_2": 0.49955, + "gen_feat_3": 486.14 + } + }, + { + "id": "t_shopping_gen_56", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.69, + "time": 44.04, + "distance": 1224.5, + "gen_feat_1": 492.29, + "gen_feat_2": 0.500032, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_57", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.68, + "time": 46.32, + "distance": 1227.05, + "gen_feat_1": 510.63, + "gen_feat_2": 0.51217, + "gen_feat_3": 489.8 + } + }, + { + "id": "t_shopping_gen_58", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.13, + "time": 45.42, + "distance": 1231.38, + "gen_feat_1": 499.25, + "gen_feat_2": 0.502657, + "gen_feat_3": 488.16 + } + }, + { + "id": "t_shopping_gen_59", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 45.04, + "distance": 1206.58, + "gen_feat_1": 488.66, + "gen_feat_2": 0.500622, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_shopping_gen_60", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.33, + "time": 46.0, + "distance": 1170.11, + "gen_feat_1": 511.4, + "gen_feat_2": 0.49549, + "gen_feat_3": 503.71 + } + }, + { + "id": "t_shopping_gen_61", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.18, + "time": 46.1, + "distance": 1190.97, + "gen_feat_1": 498.6, + "gen_feat_2": 0.501812, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_62", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.24, + "time": 45.7, + "distance": 1164.26, + "gen_feat_1": 485.26, + "gen_feat_2": 0.49031, + "gen_feat_3": 487.45 + } + }, + { + "id": "t_shopping_gen_63", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.17, + "time": 45.97, + "distance": 1190.2, + "gen_feat_1": 511.28, + "gen_feat_2": 0.51432, + "gen_feat_3": 513.58 + } + }, + { + "id": "t_shopping_gen_64", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.73, + "time": 44.03, + "distance": 1178.97, + "gen_feat_1": 487.49, + "gen_feat_2": 0.508632, + "gen_feat_3": 500.21 + } + }, + { + "id": "t_shopping_gen_65", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.67, + "time": 43.83, + "distance": 1176.27, + "gen_feat_1": 512.03, + "gen_feat_2": 0.49815, + "gen_feat_3": 501.03 + } + }, + { + "id": "t_shopping_gen_66", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.26, + "time": 44.73, + "distance": 1220.07, + "gen_feat_1": 504.64, + "gen_feat_2": 0.502789, + "gen_feat_3": 505.95 + } + }, + { + "id": "t_shopping_gen_67", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.81, + "time": 44.73, + "distance": 1180.99, + "gen_feat_1": 491.13, + "gen_feat_2": 0.488945, + "gen_feat_3": 487.4 + } + }, + { + "id": "t_shopping_gen_68", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.86, + "time": 43.67, + "distance": 1232.56, + "gen_feat_1": 512.67, + "gen_feat_2": 0.491258, + "gen_feat_3": 495.53 + } + }, + { + "id": "t_shopping_gen_69", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.0, + "time": 45.32, + "distance": 1179.79, + "gen_feat_1": 504.7, + "gen_feat_2": 0.501825, + "gen_feat_3": 494.35 + } + }, + { + "id": "t_shopping_gen_70", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 45.99, + "distance": 1206.39, + "gen_feat_1": 497.84, + "gen_feat_2": 0.509326, + "gen_feat_3": 508.37 + } + }, + { + "id": "t_shopping_gen_71", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.89, + "time": 44.23, + "distance": 1211.83, + "gen_feat_1": 489.02, + "gen_feat_2": 0.504569, + "gen_feat_3": 486.74 + } + }, + { + "id": "t_shopping_gen_72", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.25, + "time": 43.89, + "distance": 1218.83, + "gen_feat_1": 514.57, + "gen_feat_2": 0.487312, + "gen_feat_3": 491.96 + } + }, + { + "id": "t_shopping_gen_73", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 45.64, + "distance": 1171.76, + "gen_feat_1": 499.58, + "gen_feat_2": 0.499353, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_shopping_gen_74", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.51, + "time": 45.18, + "distance": 1235.16, + "gen_feat_1": 491.35, + "gen_feat_2": 0.488032, + "gen_feat_3": 508.76 + } + }, + { + "id": "t_shopping_gen_75", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.45, + "time": 45.29, + "distance": 1185.87, + "gen_feat_1": 506.16, + "gen_feat_2": 0.494622, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_shopping_gen_76", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.11, + "time": 44.39, + "distance": 1222.53, + "gen_feat_1": 507.53, + "gen_feat_2": 0.505002, + "gen_feat_3": 503.01 + } + }, + { + "id": "t_shopping_gen_77", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.93, + "time": 46.13, + "distance": 1210.75, + "gen_feat_1": 506.27, + "gen_feat_2": 0.505682, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_shopping_gen_78", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.16, + "time": 46.07, + "distance": 1210.7, + "gen_feat_1": 508.56, + "gen_feat_2": 0.487189, + "gen_feat_3": 504.12 + } + }, + { + "id": "t_shopping_gen_79", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.03, + "time": 45.66, + "distance": 1190.96, + "gen_feat_1": 489.72, + "gen_feat_2": 0.488214, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_shopping_gen_80", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.77, + "time": 45.73, + "distance": 1226.46, + "gen_feat_1": 498.85, + "gen_feat_2": 0.50612, + "gen_feat_3": 508.83 + } + }, + { + "id": "t_shopping_gen_81", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.19, + "time": 44.4, + "distance": 1207.41, + "gen_feat_1": 512.69, + "gen_feat_2": 0.49773, + "gen_feat_3": 499.57 + } + }, + { + "id": "t_shopping_gen_82", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.91, + "time": 45.81, + "distance": 1232.14, + "gen_feat_1": 501.37, + "gen_feat_2": 0.501413, + "gen_feat_3": 509.02 + } + }, + { + "id": "t_shopping_gen_83", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.46, + "time": 45.7, + "distance": 1201.06, + "gen_feat_1": 507.37, + "gen_feat_2": 0.512514, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_84", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.46, + "time": 45.7, + "distance": 1176.63, + "gen_feat_1": 500.57, + "gen_feat_2": 0.512907, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_shopping_gen_85", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.3, + "time": 44.77, + "distance": 1227.54, + "gen_feat_1": 488.72, + "gen_feat_2": 0.491267, + "gen_feat_3": 504.72 + } + }, + { + "id": "t_shopping_gen_86", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.53, + "time": 44.82, + "distance": 1227.19, + "gen_feat_1": 495.19, + "gen_feat_2": 0.506807, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_shopping_gen_87", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.76, + "time": 45.19, + "distance": 1197.27, + "gen_feat_1": 492.23, + "gen_feat_2": 0.502276, + "gen_feat_3": 497.83 + } + }, + { + "id": "t_shopping_gen_88", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.51, + "time": 46.32, + "distance": 1202.27, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500008, + "gen_feat_3": 494.37 + } + }, + { + "id": "t_shopping_gen_89", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.31, + "time": 45.09, + "distance": 1196.05, + "gen_feat_1": 488.52, + "gen_feat_2": 0.501783, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_90", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.15, + "time": 45.09, + "distance": 1187.36, + "gen_feat_1": 510.87, + "gen_feat_2": 0.48952, + "gen_feat_3": 487.44 + } + }, + { + "id": "t_shopping_gen_91", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.98, + "time": 44.28, + "distance": 1230.46, + "gen_feat_1": 494.85, + "gen_feat_2": 0.49072, + "gen_feat_3": 507.33 + } + }, + { + "id": "t_shopping_gen_92", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.46, + "time": 44.78, + "distance": 1190.65, + "gen_feat_1": 511.14, + "gen_feat_2": 0.491965, + "gen_feat_3": 510.07 + } + }, + { + "id": "t_shopping_gen_93", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 44.16, + "distance": 1232.76, + "gen_feat_1": 491.76, + "gen_feat_2": 0.49386, + "gen_feat_3": 489.99 + } + }, + { + "id": "t_shopping_gen_94", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.09, + "time": 45.07, + "distance": 1187.9, + "gen_feat_1": 500.36, + "gen_feat_2": 0.505173, + "gen_feat_3": 512.28 + } + }, + { + "id": "t_shopping_gen_95", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.29, + "time": 44.73, + "distance": 1224.17, + "gen_feat_1": 507.58, + "gen_feat_2": 0.48708, + "gen_feat_3": 511.59 + } + }, + { + "id": "t_shopping_gen_96", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.53, + "time": 43.89, + "distance": 1206.53, + "gen_feat_1": 493.71, + "gen_feat_2": 0.505153, + "gen_feat_3": 502.61 + } + }, + { + "id": "t_shopping_gen_97", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.6, + "time": 45.25, + "distance": 1198.77, + "gen_feat_1": 499.74, + "gen_feat_2": 0.499805, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_shopping_gen_98", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.94, + "time": 45.61, + "distance": 1168.51, + "gen_feat_1": 491.6, + "gen_feat_2": 0.511011, + "gen_feat_3": 491.45 + } + }, + { + "id": "t_shopping_gen_99", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.76, + "time": 45.99, + "distance": 1192.67, + "gen_feat_1": 500.07, + "gen_feat_2": 0.491787, + "gen_feat_3": 488.2 + } + }, + { + "id": "t_movie_gen_2", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.81, + "time": 138.02, + "distance": 1654.01, + "gen_feat_1": 503.91, + "gen_feat_2": 0.502664, + "gen_feat_3": 506.8 + } + }, + { + "id": "t_movie_gen_3", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.98, + "time": 133.32, + "distance": 1664.29, + "gen_feat_1": 491.47, + "gen_feat_2": 0.500325, + "gen_feat_3": 496.28 + } + }, + { + "id": "t_movie_gen_4", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.11, + "time": 136.06, + "distance": 1704.88, + "gen_feat_1": 505.19, + "gen_feat_2": 0.509953, + "gen_feat_3": 499.19 + } + }, + { + "id": "t_movie_gen_5", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.17, + "time": 136.4, + "distance": 1724.13, + "gen_feat_1": 511.77, + "gen_feat_2": 0.505076, + "gen_feat_3": 491.0 + } + }, + { + "id": "t_movie_gen_6", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.2, + "time": 137.15, + "distance": 1664.63, + "gen_feat_1": 514.48, + "gen_feat_2": 0.503771, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_movie_gen_7", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.16, + "time": 135.61, + "distance": 1726.58, + "gen_feat_1": 493.34, + "gen_feat_2": 0.493128, + "gen_feat_3": 491.4 + } + }, + { + "id": "t_movie_gen_8", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.91, + "time": 135.69, + "distance": 1678.5, + "gen_feat_1": 493.49, + "gen_feat_2": 0.506584, + "gen_feat_3": 491.95 + } + }, + { + "id": "t_movie_gen_9", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.09, + "time": 132.47, + "distance": 1682.74, + "gen_feat_1": 513.37, + "gen_feat_2": 0.496243, + "gen_feat_3": 510.52 + } + }, + { + "id": "t_movie_gen_10", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.25, + "time": 134.94, + "distance": 1683.72, + "gen_feat_1": 493.66, + "gen_feat_2": 0.502149, + "gen_feat_3": 491.38 + } + }, + { + "id": "t_movie_gen_11", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 132.2, + "distance": 1677.4, + "gen_feat_1": 513.51, + "gen_feat_2": 0.512663, + "gen_feat_3": 496.77 + } + }, + { + "id": "t_movie_gen_12", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.02, + "time": 136.12, + "distance": 1683.25, + "gen_feat_1": 486.72, + "gen_feat_2": 0.48763, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_movie_gen_13", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 131.91, + "distance": 1710.85, + "gen_feat_1": 493.33, + "gen_feat_2": 0.499006, + "gen_feat_3": 497.58 + } + }, + { + "id": "t_movie_gen_14", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.85, + "time": 137.69, + "distance": 1738.0, + "gen_feat_1": 501.65, + "gen_feat_2": 0.507629, + "gen_feat_3": 509.86 + } + }, + { + "id": "t_movie_gen_15", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.02, + "time": 133.61, + "distance": 1660.2, + "gen_feat_1": 512.64, + "gen_feat_2": 0.487548, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_movie_gen_16", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.2, + "time": 132.6, + "distance": 1669.36, + "gen_feat_1": 490.54, + "gen_feat_2": 0.507088, + "gen_feat_3": 496.37 + } + }, + { + "id": "t_movie_gen_17", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.25, + "time": 138.2, + "distance": 1711.42, + "gen_feat_1": 497.15, + "gen_feat_2": 0.513509, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_movie_gen_18", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.76, + "time": 136.31, + "distance": 1749.75, + "gen_feat_1": 514.83, + "gen_feat_2": 0.50335, + "gen_feat_3": 503.33 + } + }, + { + "id": "t_movie_gen_19", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 131.68, + "distance": 1656.52, + "gen_feat_1": 487.37, + "gen_feat_2": 0.493627, + "gen_feat_3": 508.19 + } + }, + { + "id": "t_movie_gen_20", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.9, + "time": 137.27, + "distance": 1709.53, + "gen_feat_1": 497.44, + "gen_feat_2": 0.486038, + "gen_feat_3": 502.32 + } + }, + { + "id": "t_movie_gen_21", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.83, + "time": 136.88, + "distance": 1708.94, + "gen_feat_1": 492.6, + "gen_feat_2": 0.496495, + "gen_feat_3": 490.83 + } + }, + { + "id": "t_movie_gen_22", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.12, + "time": 133.07, + "distance": 1711.62, + "gen_feat_1": 493.34, + "gen_feat_2": 0.499182, + "gen_feat_3": 499.28 + } + }, + { + "id": "t_movie_gen_23", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.12, + "time": 134.21, + "distance": 1736.25, + "gen_feat_1": 503.64, + "gen_feat_2": 0.5068, + "gen_feat_3": 489.21 + } + }, + { + "id": "t_movie_gen_24", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 132.64, + "distance": 1664.88, + "gen_feat_1": 510.09, + "gen_feat_2": 0.510289, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_movie_gen_25", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.1, + "time": 137.12, + "distance": 1701.34, + "gen_feat_1": 501.06, + "gen_feat_2": 0.49893, + "gen_feat_3": 507.73 + } + }, + { + "id": "t_movie_gen_26", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 136.45, + "distance": 1678.04, + "gen_feat_1": 494.8, + "gen_feat_2": 0.485118, + "gen_feat_3": 508.86 + } + }, + { + "id": "t_movie_gen_27", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.83, + "time": 134.67, + "distance": 1694.92, + "gen_feat_1": 503.64, + "gen_feat_2": 0.511029, + "gen_feat_3": 505.48 + } + }, + { + "id": "t_movie_gen_28", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.96, + "time": 138.62, + "distance": 1659.13, + "gen_feat_1": 491.47, + "gen_feat_2": 0.511429, + "gen_feat_3": 500.08 + } + }, + { + "id": "t_movie_gen_29", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.76, + "time": 138.64, + "distance": 1697.07, + "gen_feat_1": 498.44, + "gen_feat_2": 0.509025, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_movie_gen_30", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.39, + "distance": 1730.3, + "gen_feat_1": 510.02, + "gen_feat_2": 0.491101, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_31", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.28, + "time": 131.41, + "distance": 1685.65, + "gen_feat_1": 490.64, + "gen_feat_2": 0.485642, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_movie_gen_32", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.93, + "time": 134.98, + "distance": 1695.11, + "gen_feat_1": 501.21, + "gen_feat_2": 0.50543, + "gen_feat_3": 499.51 + } + }, + { + "id": "t_movie_gen_33", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.87, + "time": 137.83, + "distance": 1715.38, + "gen_feat_1": 513.71, + "gen_feat_2": 0.493568, + "gen_feat_3": 514.01 + } + }, + { + "id": "t_movie_gen_34", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.81, + "time": 132.4, + "distance": 1663.09, + "gen_feat_1": 506.91, + "gen_feat_2": 0.510638, + "gen_feat_3": 501.83 + } + }, + { + "id": "t_movie_gen_35", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.24, + "time": 136.79, + "distance": 1694.27, + "gen_feat_1": 510.84, + "gen_feat_2": 0.507452, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_movie_gen_36", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.16, + "time": 136.15, + "distance": 1670.24, + "gen_feat_1": 502.99, + "gen_feat_2": 0.495856, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_37", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.3, + "time": 136.48, + "distance": 1719.06, + "gen_feat_1": 512.77, + "gen_feat_2": 0.488773, + "gen_feat_3": 505.19 + } + }, + { + "id": "t_movie_gen_38", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.89, + "time": 137.8, + "distance": 1682.43, + "gen_feat_1": 514.67, + "gen_feat_2": 0.508214, + "gen_feat_3": 504.71 + } + }, + { + "id": "t_movie_gen_39", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.88, + "time": 136.94, + "distance": 1652.85, + "gen_feat_1": 499.19, + "gen_feat_2": 0.500729, + "gen_feat_3": 511.08 + } + }, + { + "id": "t_movie_gen_40", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.75, + "time": 136.81, + "distance": 1673.83, + "gen_feat_1": 510.5, + "gen_feat_2": 0.496266, + "gen_feat_3": 512.35 + } + }, + { + "id": "t_movie_gen_41", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.84, + "time": 133.13, + "distance": 1698.79, + "gen_feat_1": 504.79, + "gen_feat_2": 0.491761, + "gen_feat_3": 489.88 + } + }, + { + "id": "t_movie_gen_42", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.79, + "time": 132.71, + "distance": 1654.02, + "gen_feat_1": 488.54, + "gen_feat_2": 0.496646, + "gen_feat_3": 506.89 + } + }, + { + "id": "t_movie_gen_43", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.03, + "time": 135.73, + "distance": 1687.52, + "gen_feat_1": 489.12, + "gen_feat_2": 0.50799, + "gen_feat_3": 499.94 + } + }, + { + "id": "t_movie_gen_44", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.09, + "time": 138.68, + "distance": 1703.05, + "gen_feat_1": 510.12, + "gen_feat_2": 0.485551, + "gen_feat_3": 502.13 + } + }, + { + "id": "t_movie_gen_45", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.86, + "time": 133.42, + "distance": 1652.65, + "gen_feat_1": 488.6, + "gen_feat_2": 0.510397, + "gen_feat_3": 509.98 + } + }, + { + "id": "t_movie_gen_46", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.97, + "time": 131.94, + "distance": 1673.56, + "gen_feat_1": 486.56, + "gen_feat_2": 0.505523, + "gen_feat_3": 501.82 + } + }, + { + "id": "t_movie_gen_47", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.0, + "time": 133.55, + "distance": 1671.34, + "gen_feat_1": 488.32, + "gen_feat_2": 0.49915, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_movie_gen_48", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.06, + "time": 138.36, + "distance": 1677.66, + "gen_feat_1": 497.58, + "gen_feat_2": 0.497849, + "gen_feat_3": 488.29 + } + }, + { + "id": "t_movie_gen_49", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 133.95, + "distance": 1742.48, + "gen_feat_1": 495.5, + "gen_feat_2": 0.511503, + "gen_feat_3": 491.31 + } + }, + { + "id": "t_movie_gen_50", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.77, + "time": 135.54, + "distance": 1710.41, + "gen_feat_1": 487.97, + "gen_feat_2": 0.508317, + "gen_feat_3": 490.49 + } + }, + { + "id": "t_movie_gen_51", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.77, + "time": 135.9, + "distance": 1664.29, + "gen_feat_1": 513.14, + "gen_feat_2": 0.507714, + "gen_feat_3": 487.99 + } + }, + { + "id": "t_movie_gen_52", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.74, + "time": 133.36, + "distance": 1679.04, + "gen_feat_1": 502.14, + "gen_feat_2": 0.489374, + "gen_feat_3": 501.0 + } + }, + { + "id": "t_movie_gen_53", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.75, + "time": 137.75, + "distance": 1727.9, + "gen_feat_1": 494.43, + "gen_feat_2": 0.492795, + "gen_feat_3": 507.56 + } + }, + { + "id": "t_movie_gen_54", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 137.23, + "distance": 1749.88, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514964, + "gen_feat_3": 513.51 + } + }, + { + "id": "t_movie_gen_55", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.27, + "time": 131.7, + "distance": 1671.69, + "gen_feat_1": 491.71, + "gen_feat_2": 0.507637, + "gen_feat_3": 496.63 + } + }, + { + "id": "t_movie_gen_56", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.25, + "time": 133.82, + "distance": 1744.69, + "gen_feat_1": 513.96, + "gen_feat_2": 0.486719, + "gen_feat_3": 505.59 + } + }, + { + "id": "t_movie_gen_57", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.99, + "distance": 1687.02, + "gen_feat_1": 495.73, + "gen_feat_2": 0.497053, + "gen_feat_3": 485.08 + } + }, + { + "id": "t_movie_gen_58", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 134.0, + "distance": 1717.93, + "gen_feat_1": 498.58, + "gen_feat_2": 0.514512, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_movie_gen_59", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 135.99, + "distance": 1669.61, + "gen_feat_1": 506.91, + "gen_feat_2": 0.486343, + "gen_feat_3": 513.29 + } + }, + { + "id": "t_movie_gen_60", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 137.16, + "distance": 1727.65, + "gen_feat_1": 511.78, + "gen_feat_2": 0.498191, + "gen_feat_3": 495.09 + } + }, + { + "id": "t_movie_gen_61", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.06, + "time": 131.51, + "distance": 1688.72, + "gen_feat_1": 501.65, + "gen_feat_2": 0.503774, + "gen_feat_3": 494.98 + } + }, + { + "id": "t_movie_gen_62", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 134.94, + "distance": 1688.34, + "gen_feat_1": 486.17, + "gen_feat_2": 0.506252, + "gen_feat_3": 499.8 + } + }, + { + "id": "t_movie_gen_63", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.0, + "time": 132.52, + "distance": 1696.65, + "gen_feat_1": 514.69, + "gen_feat_2": 0.493209, + "gen_feat_3": 485.24 + } + }, + { + "id": "t_movie_gen_64", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.73, + "time": 131.33, + "distance": 1699.32, + "gen_feat_1": 494.73, + "gen_feat_2": 0.500638, + "gen_feat_3": 507.36 + } + }, + { + "id": "t_movie_gen_65", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.28, + "time": 135.57, + "distance": 1672.37, + "gen_feat_1": 512.61, + "gen_feat_2": 0.49003, + "gen_feat_3": 498.67 + } + }, + { + "id": "t_movie_gen_66", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.81, + "time": 133.8, + "distance": 1700.55, + "gen_feat_1": 512.0, + "gen_feat_2": 0.486179, + "gen_feat_3": 501.33 + } + }, + { + "id": "t_movie_gen_67", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.03, + "time": 131.77, + "distance": 1745.74, + "gen_feat_1": 503.3, + "gen_feat_2": 0.51441, + "gen_feat_3": 486.9 + } + }, + { + "id": "t_movie_gen_68", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.9, + "time": 137.31, + "distance": 1655.07, + "gen_feat_1": 485.6, + "gen_feat_2": 0.49856, + "gen_feat_3": 495.04 + } + }, + { + "id": "t_movie_gen_69", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.19, + "time": 137.9, + "distance": 1713.23, + "gen_feat_1": 510.23, + "gen_feat_2": 0.490473, + "gen_feat_3": 492.48 + } + }, + { + "id": "t_movie_gen_70", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.92, + "time": 137.74, + "distance": 1742.03, + "gen_feat_1": 497.94, + "gen_feat_2": 0.514756, + "gen_feat_3": 487.31 + } + }, + { + "id": "t_movie_gen_71", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.28, + "time": 134.06, + "distance": 1654.96, + "gen_feat_1": 510.56, + "gen_feat_2": 0.492021, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_movie_gen_72", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 135.82, + "distance": 1738.49, + "gen_feat_1": 500.42, + "gen_feat_2": 0.493135, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_73", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 134.69, + "distance": 1663.19, + "gen_feat_1": 491.2, + "gen_feat_2": 0.505794, + "gen_feat_3": 504.69 + } + }, + { + "id": "t_movie_gen_74", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.82, + "time": 132.56, + "distance": 1679.26, + "gen_feat_1": 497.39, + "gen_feat_2": 0.485217, + "gen_feat_3": 513.12 + } + }, + { + "id": "t_movie_gen_75", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.18, + "time": 134.95, + "distance": 1745.08, + "gen_feat_1": 491.08, + "gen_feat_2": 0.495277, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_movie_gen_76", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.16, + "time": 138.62, + "distance": 1666.98, + "gen_feat_1": 501.07, + "gen_feat_2": 0.506814, + "gen_feat_3": 489.44 + } + }, + { + "id": "t_movie_gen_77", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.76, + "time": 130.95, + "distance": 1675.39, + "gen_feat_1": 513.23, + "gen_feat_2": 0.496512, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_movie_gen_78", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.99, + "time": 132.12, + "distance": 1674.54, + "gen_feat_1": 495.99, + "gen_feat_2": 0.496439, + "gen_feat_3": 506.49 + } + }, + { + "id": "t_movie_gen_79", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.84, + "time": 132.9, + "distance": 1698.58, + "gen_feat_1": 486.83, + "gen_feat_2": 0.487385, + "gen_feat_3": 489.3 + } + }, + { + "id": "t_movie_gen_80", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 135.25, + "distance": 1703.48, + "gen_feat_1": 497.71, + "gen_feat_2": 0.506091, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_movie_gen_81", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.08, + "time": 138.34, + "distance": 1706.78, + "gen_feat_1": 501.18, + "gen_feat_2": 0.503416, + "gen_feat_3": 493.11 + } + }, + { + "id": "t_movie_gen_82", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.95, + "time": 132.28, + "distance": 1658.35, + "gen_feat_1": 488.13, + "gen_feat_2": 0.514958, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_83", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 135.04, + "distance": 1663.79, + "gen_feat_1": 495.07, + "gen_feat_2": 0.489223, + "gen_feat_3": 514.52 + } + }, + { + "id": "t_movie_gen_84", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.76, + "time": 137.41, + "distance": 1703.65, + "gen_feat_1": 504.9, + "gen_feat_2": 0.503529, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_movie_gen_85", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.08, + "time": 135.55, + "distance": 1691.79, + "gen_feat_1": 503.38, + "gen_feat_2": 0.5004, + "gen_feat_3": 510.63 + } + }, + { + "id": "t_movie_gen_86", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.24, + "time": 133.11, + "distance": 1689.53, + "gen_feat_1": 509.79, + "gen_feat_2": 0.49881, + "gen_feat_3": 488.86 + } + }, + { + "id": "t_movie_gen_87", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.89, + "time": 137.15, + "distance": 1698.06, + "gen_feat_1": 503.82, + "gen_feat_2": 0.50464, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_88", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.13, + "time": 131.18, + "distance": 1660.59, + "gen_feat_1": 492.85, + "gen_feat_2": 0.514114, + "gen_feat_3": 513.82 + } + }, + { + "id": "t_movie_gen_89", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.87, + "time": 135.02, + "distance": 1741.57, + "gen_feat_1": 501.92, + "gen_feat_2": 0.508398, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_90", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.28, + "time": 137.35, + "distance": 1718.09, + "gen_feat_1": 488.68, + "gen_feat_2": 0.49537, + "gen_feat_3": 493.95 + } + }, + { + "id": "t_movie_gen_91", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 137.3, + "distance": 1693.34, + "gen_feat_1": 493.19, + "gen_feat_2": 0.495672, + "gen_feat_3": 488.25 + } + }, + { + "id": "t_movie_gen_92", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.83, + "time": 137.58, + "distance": 1744.3, + "gen_feat_1": 491.56, + "gen_feat_2": 0.498387, + "gen_feat_3": 511.69 + } + }, + { + "id": "t_movie_gen_93", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.91, + "time": 133.34, + "distance": 1702.93, + "gen_feat_1": 488.01, + "gen_feat_2": 0.502779, + "gen_feat_3": 491.18 + } + }, + { + "id": "t_movie_gen_94", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 134.1, + "distance": 1680.7, + "gen_feat_1": 497.7, + "gen_feat_2": 0.497436, + "gen_feat_3": 502.47 + } + }, + { + "id": "t_movie_gen_95", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 136.67, + "distance": 1705.0, + "gen_feat_1": 488.28, + "gen_feat_2": 0.487878, + "gen_feat_3": 495.8 + } + }, + { + "id": "t_movie_gen_96", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.9, + "time": 134.07, + "distance": 1659.49, + "gen_feat_1": 492.47, + "gen_feat_2": 0.492451, + "gen_feat_3": 511.78 + } + }, + { + "id": "t_movie_gen_97", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.21, + "time": 134.31, + "distance": 1734.61, + "gen_feat_1": 493.2, + "gen_feat_2": 0.488477, + "gen_feat_3": 503.93 + } + }, + { + "id": "t_movie_gen_98", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 135.67, + "distance": 1729.26, + "gen_feat_1": 489.64, + "gen_feat_2": 0.491387, + "gen_feat_3": 506.86 + } + }, + { + "id": "t_movie_gen_99", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.79, + "time": 133.64, + "distance": 1673.71, + "gen_feat_1": 505.04, + "gen_feat_2": 0.505422, + "gen_feat_3": 513.37 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_dining", + "kind": "TASK", + "task_id": "t_dining" + }, + { + "id": "n_shopping", + "kind": "TASK", + "task_id": "t_shopping" + }, + { + "id": "n_movie", + "kind": "TASK", + "task_id": "t_movie" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "time": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "distance": { + "neutral": 0, + "compose": { + "seq": { + "fn": "MAX" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "c_within_2km", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "distance", + "op": "<=", + "value": 2000 + }, + { + "id": "c_time_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "time", + "op": "<=", + "value": 240, + "hard": false + }, + { + "id": "c_cost_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 100, + "hard": false + }, + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 50.07, + "hard": true + }, + { + "id": "gen_c_local_t_dining_time_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_dining" + ], + "attribute_id": "time", + "op": "<=", + "value": 59.79, + "hard": true + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_dining", + "t_shopping" + ], + "hard": true + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_dining", + "t_movie" + ], + "hard": true + } + ], + "objective": { + "type": "MULTI", + "targets": [ + "cost", + "distance", + "gen_feat_1" + ], + "weights": { + "cost": 0.34, + "distance": 0.33, + "gen_feat_1": 0.33 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/instances/zhang2014-entertainment-planner-running-example_multi_soft.json b/experimentation/instances/zhang2014-entertainment-planner-running-example_multi_soft.json new file mode 100644 index 0000000..dcacb72 --- /dev/null +++ b/experimentation/instances/zhang2014-entertainment-planner-running-example_multi_soft.json @@ -0,0 +1,4535 @@ +{ + "metadata": { + "id": "zhang2014-entertainment-planner-running-example_multi_soft", + "name": "Personal Entertainment Planner (Zhang et al. 2014) [multi, soft]", + "version": "1.0.0", + "created_at": "2026-02-12T08:35:05Z", + "description": "Modeled from the motivating example in 'Context-aware Generic Service Discovery and Service Composition' (IEEE MobServ 2014).", + "paper": { + "title": "Context-aware Generic Service Discovery and Service Composition", + "authors": "Y. Zhang et al.", + "year": 2014, + "doi": "10.1109/MobServ.2014.27" + } + }, + "features": [ + { + "id": "cost", + "name": "Total money cost (USD)", + "direction": "MINIMIZE", + "unit": "usd", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "time", + "name": "Total time cost (minutes)", + "direction": "MINIMIZE", + "unit": "min", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1440 + } + }, + { + "id": "distance", + "name": "Distance from user's current location (meters)", + "direction": "MINIMIZE", + "unit": "m", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 50000 + } + }, + { + "id": "gen_feat_1", + "name": "Generated feature gen_feat_1", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + }, + { + "id": "gen_feat_2", + "name": "Generated feature gen_feat_2", + "direction": "MAXIMIZE", + "unit": "ratio", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1 + } + }, + { + "id": "gen_feat_3", + "name": "Generated feature gen_feat_3", + "direction": "MINIMIZE", + "unit": "unit", + "scale": "RATIO", + "valid_range": { + "min": 0, + "max": 1000 + } + } + ], + "providers": [ + { + "id": "p_rest_autre_saison", + "name": "Restaurant L’Autre Saison" + }, + { + "id": "p_cinema_banque_scotia", + "name": "Cinema Banque Scotia Montreal" + }, + { + "id": "p_seven_night_club", + "name": "Seven Night Club" + }, + { + "id": "p_local_shopping", + "name": "Local Shopping (nearby venue)" + }, + { + "id": "p_gen_shared", + "name": "Generated Shared Provider" + }, + { + "id": "p_gen_1", + "name": "Generated Provider p_gen_1" + }, + { + "id": "p_gen_2", + "name": "Generated Provider p_gen_2" + }, + { + "id": "p_gen_3", + "name": "Generated Provider p_gen_3" + }, + { + "id": "p_gen_4", + "name": "Generated Provider p_gen_4" + }, + { + "id": "p_gen_5", + "name": "Generated Provider p_gen_5" + } + ], + "tasks": [ + { + "id": "t_dining", + "name": "Restaurant / Dining activity" + }, + { + "id": "t_shopping", + "name": "Shopping activity" + }, + { + "id": "t_movie", + "name": "Movie activity" + } + ], + "candidates": [ + { + "id": "c_dining_autre_saison", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison", + "features": { + "cost": 20, + "time": 60, + "distance": 1600, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_dining_seven_night_club", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Seven Night Club", + "features": { + "cost": 20, + "time": 60, + "distance": 1800, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_shopping_local", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue", + "features": { + "cost": 20, + "time": 45, + "distance": 1200, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "c_movie_the_help_banque_scotia", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal", + "features": { + "cost": 10, + "time": 135, + "distance": 1700, + "gen_feat_1": 500.0, + "gen_feat_2": 0.5, + "gen_feat_3": 500.0 + } + }, + { + "id": "t_dining_gen_1", + "task_id": "t_dining", + "provider_id": "p_gen_shared", + "name": "Dinner at Restaurant L’Autre Saison (Gen Shared)", + "features": { + "cost": 20.2, + "time": 59.79, + "distance": 1570.05, + "gen_feat_1": 508.24, + "gen_feat_2": 0.514901, + "gen_feat_3": 509.78 + } + }, + { + "id": "t_shopping_gen_1", + "task_id": "t_shopping", + "provider_id": "p_gen_shared", + "name": "Shopping at a nearby venue (Gen Shared)", + "features": { + "cost": 19.87, + "time": 44.98, + "distance": 1189.95, + "gen_feat_1": 485.24, + "gen_feat_2": 0.486287, + "gen_feat_3": 500.42 + } + }, + { + "id": "t_movie_gen_1", + "task_id": "t_movie", + "provider_id": "p_gen_shared", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen Shared)", + "features": { + "cost": 9.82, + "time": 134.28, + "distance": 1742.9, + "gen_feat_1": 512.03, + "gen_feat_2": 0.505972, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_dining_gen_2", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.53, + "time": 59.13, + "distance": 1559.02, + "gen_feat_1": 498.66, + "gen_feat_2": 0.488957, + "gen_feat_3": 503.61 + } + }, + { + "id": "t_dining_gen_3", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.94, + "time": 58.5, + "distance": 1591.09, + "gen_feat_1": 495.96, + "gen_feat_2": 0.504969, + "gen_feat_3": 506.77 + } + }, + { + "id": "t_dining_gen_4", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.8, + "time": 61.46, + "distance": 1629.91, + "gen_feat_1": 510.53, + "gen_feat_2": 0.508, + "gen_feat_3": 491.98 + } + }, + { + "id": "t_dining_gen_5", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.22, + "time": 60.39, + "distance": 1564.48, + "gen_feat_1": 491.41, + "gen_feat_2": 0.490673, + "gen_feat_3": 490.61 + } + }, + { + "id": "t_dining_gen_6", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.38, + "time": 58.67, + "distance": 1626.15, + "gen_feat_1": 488.5, + "gen_feat_2": 0.49348, + "gen_feat_3": 495.75 + } + }, + { + "id": "t_dining_gen_7", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.18, + "time": 60.72, + "distance": 1555.22, + "gen_feat_1": 505.8, + "gen_feat_2": 0.506719, + "gen_feat_3": 499.33 + } + }, + { + "id": "t_dining_gen_8", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.43, + "time": 59.64, + "distance": 1598.13, + "gen_feat_1": 503.89, + "gen_feat_2": 0.506945, + "gen_feat_3": 508.17 + } + }, + { + "id": "t_dining_gen_9", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.64, + "time": 60.54, + "distance": 1604.33, + "gen_feat_1": 486.84, + "gen_feat_2": 0.506628, + "gen_feat_3": 501.62 + } + }, + { + "id": "t_dining_gen_10", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 60.17, + "distance": 1616.85, + "gen_feat_1": 507.44, + "gen_feat_2": 0.489997, + "gen_feat_3": 502.16 + } + }, + { + "id": "t_dining_gen_11", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.68, + "time": 59.16, + "distance": 1620.42, + "gen_feat_1": 507.98, + "gen_feat_2": 0.488942, + "gen_feat_3": 489.19 + } + }, + { + "id": "t_dining_gen_12", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.74, + "time": 59.04, + "distance": 1602.16, + "gen_feat_1": 504.58, + "gen_feat_2": 0.489389, + "gen_feat_3": 507.41 + } + }, + { + "id": "t_dining_gen_13", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.47, + "time": 58.89, + "distance": 1622.97, + "gen_feat_1": 492.31, + "gen_feat_2": 0.503154, + "gen_feat_3": 508.55 + } + }, + { + "id": "t_dining_gen_14", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.72, + "time": 58.91, + "distance": 1626.35, + "gen_feat_1": 509.41, + "gen_feat_2": 0.490291, + "gen_feat_3": 514.74 + } + }, + { + "id": "t_dining_gen_15", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.59, + "time": 60.67, + "distance": 1631.73, + "gen_feat_1": 493.43, + "gen_feat_2": 0.498961, + "gen_feat_3": 492.15 + } + }, + { + "id": "t_dining_gen_16", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.21, + "time": 59.57, + "distance": 1621.68, + "gen_feat_1": 502.04, + "gen_feat_2": 0.491944, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_dining_gen_17", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.33, + "time": 59.99, + "distance": 1602.82, + "gen_feat_1": 513.49, + "gen_feat_2": 0.510425, + "gen_feat_3": 506.46 + } + }, + { + "id": "t_dining_gen_18", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.02, + "time": 60.13, + "distance": 1639.2, + "gen_feat_1": 498.4, + "gen_feat_2": 0.499582, + "gen_feat_3": 504.62 + } + }, + { + "id": "t_dining_gen_19", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.03, + "time": 60.73, + "distance": 1642.13, + "gen_feat_1": 507.63, + "gen_feat_2": 0.500514, + "gen_feat_3": 495.73 + } + }, + { + "id": "t_dining_gen_20", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.33, + "time": 59.96, + "distance": 1568.96, + "gen_feat_1": 488.36, + "gen_feat_2": 0.514752, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_dining_gen_21", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.8, + "time": 58.42, + "distance": 1555.46, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486429, + "gen_feat_3": 488.41 + } + }, + { + "id": "t_dining_gen_22", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.66, + "time": 61.62, + "distance": 1580.67, + "gen_feat_1": 491.06, + "gen_feat_2": 0.506184, + "gen_feat_3": 501.23 + } + }, + { + "id": "t_dining_gen_23", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.42, + "time": 61.78, + "distance": 1622.72, + "gen_feat_1": 490.83, + "gen_feat_2": 0.489949, + "gen_feat_3": 487.73 + } + }, + { + "id": "t_dining_gen_24", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.71, + "time": 59.51, + "distance": 1580.85, + "gen_feat_1": 501.15, + "gen_feat_2": 0.50297, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_25", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.42, + "time": 61.41, + "distance": 1578.66, + "gen_feat_1": 507.39, + "gen_feat_2": 0.499268, + "gen_feat_3": 490.28 + } + }, + { + "id": "t_dining_gen_26", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.55, + "time": 58.26, + "distance": 1560.85, + "gen_feat_1": 492.17, + "gen_feat_2": 0.492399, + "gen_feat_3": 511.94 + } + }, + { + "id": "t_dining_gen_27", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.48, + "time": 58.34, + "distance": 1631.2, + "gen_feat_1": 498.39, + "gen_feat_2": 0.490821, + "gen_feat_3": 491.03 + } + }, + { + "id": "t_dining_gen_28", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.04, + "time": 61.28, + "distance": 1606.8, + "gen_feat_1": 512.73, + "gen_feat_2": 0.509267, + "gen_feat_3": 494.46 + } + }, + { + "id": "t_dining_gen_29", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.76, + "time": 60.3, + "distance": 1569.61, + "gen_feat_1": 490.22, + "gen_feat_2": 0.496831, + "gen_feat_3": 496.53 + } + }, + { + "id": "t_dining_gen_30", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.71, + "time": 60.3, + "distance": 1623.3, + "gen_feat_1": 500.21, + "gen_feat_2": 0.496569, + "gen_feat_3": 498.99 + } + }, + { + "id": "t_dining_gen_31", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.86, + "time": 59.05, + "distance": 1588.58, + "gen_feat_1": 485.96, + "gen_feat_2": 0.512749, + "gen_feat_3": 498.55 + } + }, + { + "id": "t_dining_gen_32", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.8, + "time": 59.8, + "distance": 1560.3, + "gen_feat_1": 512.24, + "gen_feat_2": 0.486102, + "gen_feat_3": 508.8 + } + }, + { + "id": "t_dining_gen_33", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.49, + "time": 61.12, + "distance": 1612.82, + "gen_feat_1": 506.05, + "gen_feat_2": 0.504153, + "gen_feat_3": 510.28 + } + }, + { + "id": "t_dining_gen_34", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.66, + "time": 58.74, + "distance": 1627.51, + "gen_feat_1": 494.47, + "gen_feat_2": 0.509322, + "gen_feat_3": 485.53 + } + }, + { + "id": "t_dining_gen_35", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.14, + "time": 60.57, + "distance": 1626.08, + "gen_feat_1": 500.78, + "gen_feat_2": 0.513739, + "gen_feat_3": 510.69 + } + }, + { + "id": "t_dining_gen_36", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.57, + "time": 58.38, + "distance": 1610.88, + "gen_feat_1": 495.23, + "gen_feat_2": 0.509726, + "gen_feat_3": 512.08 + } + }, + { + "id": "t_dining_gen_37", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.41, + "distance": 1575.46, + "gen_feat_1": 512.15, + "gen_feat_2": 0.492042, + "gen_feat_3": 505.13 + } + }, + { + "id": "t_dining_gen_38", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.22, + "time": 59.29, + "distance": 1557.64, + "gen_feat_1": 489.83, + "gen_feat_2": 0.49146, + "gen_feat_3": 495.3 + } + }, + { + "id": "t_dining_gen_39", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.59, + "time": 61.53, + "distance": 1562.65, + "gen_feat_1": 495.8, + "gen_feat_2": 0.496923, + "gen_feat_3": 507.91 + } + }, + { + "id": "t_dining_gen_40", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.43, + "time": 60.01, + "distance": 1604.0, + "gen_feat_1": 500.49, + "gen_feat_2": 0.514685, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_41", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.58, + "time": 60.72, + "distance": 1645.52, + "gen_feat_1": 487.19, + "gen_feat_2": 0.508959, + "gen_feat_3": 497.39 + } + }, + { + "id": "t_dining_gen_42", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.2, + "time": 59.26, + "distance": 1581.92, + "gen_feat_1": 509.7, + "gen_feat_2": 0.513201, + "gen_feat_3": 491.13 + } + }, + { + "id": "t_dining_gen_43", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.45, + "time": 60.26, + "distance": 1568.18, + "gen_feat_1": 493.86, + "gen_feat_2": 0.514555, + "gen_feat_3": 489.48 + } + }, + { + "id": "t_dining_gen_44", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.58, + "time": 58.5, + "distance": 1617.8, + "gen_feat_1": 491.08, + "gen_feat_2": 0.513671, + "gen_feat_3": 486.88 + } + }, + { + "id": "t_dining_gen_45", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.68, + "time": 61.23, + "distance": 1579.97, + "gen_feat_1": 509.82, + "gen_feat_2": 0.504088, + "gen_feat_3": 512.95 + } + }, + { + "id": "t_dining_gen_46", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 60.56, + "distance": 1641.45, + "gen_feat_1": 499.89, + "gen_feat_2": 0.510488, + "gen_feat_3": 491.3 + } + }, + { + "id": "t_dining_gen_47", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.94, + "time": 58.84, + "distance": 1629.37, + "gen_feat_1": 494.2, + "gen_feat_2": 0.49711, + "gen_feat_3": 496.8 + } + }, + { + "id": "t_dining_gen_48", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.23, + "time": 58.97, + "distance": 1607.14, + "gen_feat_1": 485.39, + "gen_feat_2": 0.485086, + "gen_feat_3": 504.57 + } + }, + { + "id": "t_dining_gen_49", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.47, + "time": 59.57, + "distance": 1615.57, + "gen_feat_1": 495.03, + "gen_feat_2": 0.503496, + "gen_feat_3": 509.51 + } + }, + { + "id": "t_dining_gen_50", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.7, + "distance": 1583.69, + "gen_feat_1": 489.31, + "gen_feat_2": 0.498993, + "gen_feat_3": 498.25 + } + }, + { + "id": "t_dining_gen_51", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.06, + "time": 60.11, + "distance": 1630.7, + "gen_feat_1": 507.83, + "gen_feat_2": 0.497927, + "gen_feat_3": 485.62 + } + }, + { + "id": "t_dining_gen_52", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.53, + "time": 58.59, + "distance": 1646.13, + "gen_feat_1": 489.54, + "gen_feat_2": 0.503777, + "gen_feat_3": 487.65 + } + }, + { + "id": "t_dining_gen_53", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.9, + "time": 58.5, + "distance": 1634.44, + "gen_feat_1": 514.43, + "gen_feat_2": 0.508093, + "gen_feat_3": 499.44 + } + }, + { + "id": "t_dining_gen_54", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.18, + "time": 58.68, + "distance": 1576.83, + "gen_feat_1": 491.93, + "gen_feat_2": 0.485409, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_dining_gen_55", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.05, + "time": 61.0, + "distance": 1581.79, + "gen_feat_1": 489.92, + "gen_feat_2": 0.49016, + "gen_feat_3": 513.4 + } + }, + { + "id": "t_dining_gen_56", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.18, + "time": 61.73, + "distance": 1637.68, + "gen_feat_1": 492.48, + "gen_feat_2": 0.497966, + "gen_feat_3": 508.66 + } + }, + { + "id": "t_dining_gen_57", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.2, + "time": 61.78, + "distance": 1646.08, + "gen_feat_1": 508.92, + "gen_feat_2": 0.500426, + "gen_feat_3": 499.7 + } + }, + { + "id": "t_dining_gen_58", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.57, + "time": 59.32, + "distance": 1580.58, + "gen_feat_1": 509.74, + "gen_feat_2": 0.510379, + "gen_feat_3": 512.86 + } + }, + { + "id": "t_dining_gen_59", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.54, + "time": 59.3, + "distance": 1570.05, + "gen_feat_1": 486.4, + "gen_feat_2": 0.503502, + "gen_feat_3": 498.65 + } + }, + { + "id": "t_dining_gen_60", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.18, + "time": 61.43, + "distance": 1636.11, + "gen_feat_1": 485.66, + "gen_feat_2": 0.498532, + "gen_feat_3": 506.32 + } + }, + { + "id": "t_dining_gen_61", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.01, + "time": 59.61, + "distance": 1626.73, + "gen_feat_1": 507.2, + "gen_feat_2": 0.505098, + "gen_feat_3": 499.85 + } + }, + { + "id": "t_dining_gen_62", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.22, + "time": 59.78, + "distance": 1646.36, + "gen_feat_1": 500.64, + "gen_feat_2": 0.500049, + "gen_feat_3": 504.88 + } + }, + { + "id": "t_dining_gen_63", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 20.11, + "time": 59.7, + "distance": 1621.52, + "gen_feat_1": 494.18, + "gen_feat_2": 0.498313, + "gen_feat_3": 506.17 + } + }, + { + "id": "t_dining_gen_64", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.71, + "time": 61.36, + "distance": 1568.12, + "gen_feat_1": 493.75, + "gen_feat_2": 0.505406, + "gen_feat_3": 512.82 + } + }, + { + "id": "t_dining_gen_65", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.4, + "time": 58.28, + "distance": 1604.89, + "gen_feat_1": 487.06, + "gen_feat_2": 0.502445, + "gen_feat_3": 511.12 + } + }, + { + "id": "t_dining_gen_66", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 59.57, + "distance": 1581.66, + "gen_feat_1": 513.25, + "gen_feat_2": 0.493068, + "gen_feat_3": 505.54 + } + }, + { + "id": "t_dining_gen_67", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.21, + "time": 60.81, + "distance": 1606.42, + "gen_feat_1": 493.36, + "gen_feat_2": 0.50459, + "gen_feat_3": 493.01 + } + }, + { + "id": "t_dining_gen_68", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 59.09, + "distance": 1611.43, + "gen_feat_1": 505.83, + "gen_feat_2": 0.502644, + "gen_feat_3": 504.4 + } + }, + { + "id": "t_dining_gen_69", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.92, + "time": 61.04, + "distance": 1579.9, + "gen_feat_1": 512.7, + "gen_feat_2": 0.488813, + "gen_feat_3": 500.85 + } + }, + { + "id": "t_dining_gen_70", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.74, + "time": 59.83, + "distance": 1615.86, + "gen_feat_1": 505.67, + "gen_feat_2": 0.48967, + "gen_feat_3": 503.59 + } + }, + { + "id": "t_dining_gen_71", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 61.74, + "distance": 1585.25, + "gen_feat_1": 495.74, + "gen_feat_2": 0.490106, + "gen_feat_3": 499.93 + } + }, + { + "id": "t_dining_gen_72", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.9, + "time": 58.61, + "distance": 1604.96, + "gen_feat_1": 509.49, + "gen_feat_2": 0.512456, + "gen_feat_3": 505.29 + } + }, + { + "id": "t_dining_gen_73", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.41, + "time": 59.23, + "distance": 1631.69, + "gen_feat_1": 507.39, + "gen_feat_2": 0.504155, + "gen_feat_3": 514.37 + } + }, + { + "id": "t_dining_gen_74", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.5, + "time": 58.7, + "distance": 1628.56, + "gen_feat_1": 514.96, + "gen_feat_2": 0.498875, + "gen_feat_3": 512.16 + } + }, + { + "id": "t_dining_gen_75", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.83, + "time": 61.78, + "distance": 1589.19, + "gen_feat_1": 501.13, + "gen_feat_2": 0.504679, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_dining_gen_76", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 20.02, + "time": 61.78, + "distance": 1596.36, + "gen_feat_1": 511.57, + "gen_feat_2": 0.51185, + "gen_feat_3": 493.99 + } + }, + { + "id": "t_dining_gen_77", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.38, + "time": 59.52, + "distance": 1573.49, + "gen_feat_1": 513.61, + "gen_feat_2": 0.50886, + "gen_feat_3": 505.08 + } + }, + { + "id": "t_dining_gen_78", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.28, + "time": 59.03, + "distance": 1628.26, + "gen_feat_1": 513.77, + "gen_feat_2": 0.508209, + "gen_feat_3": 504.63 + } + }, + { + "id": "t_dining_gen_79", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.75, + "time": 60.98, + "distance": 1603.39, + "gen_feat_1": 510.74, + "gen_feat_2": 0.51442, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_dining_gen_80", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.34, + "time": 59.39, + "distance": 1607.15, + "gen_feat_1": 489.01, + "gen_feat_2": 0.508841, + "gen_feat_3": 503.65 + } + }, + { + "id": "t_dining_gen_81", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.78, + "time": 61.32, + "distance": 1606.79, + "gen_feat_1": 494.77, + "gen_feat_2": 0.498081, + "gen_feat_3": 490.68 + } + }, + { + "id": "t_dining_gen_82", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 20.0, + "time": 60.47, + "distance": 1578.03, + "gen_feat_1": 505.85, + "gen_feat_2": 0.496498, + "gen_feat_3": 494.3 + } + }, + { + "id": "t_dining_gen_83", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 19.59, + "time": 60.4, + "distance": 1576.41, + "gen_feat_1": 487.54, + "gen_feat_2": 0.490813, + "gen_feat_3": 506.97 + } + }, + { + "id": "t_dining_gen_84", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.45, + "time": 58.59, + "distance": 1635.41, + "gen_feat_1": 507.53, + "gen_feat_2": 0.499359, + "gen_feat_3": 511.49 + } + }, + { + "id": "t_dining_gen_85", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.55, + "time": 59.37, + "distance": 1578.95, + "gen_feat_1": 500.14, + "gen_feat_2": 0.504331, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_dining_gen_86", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.82, + "time": 59.11, + "distance": 1556.1, + "gen_feat_1": 513.36, + "gen_feat_2": 0.512958, + "gen_feat_3": 493.44 + } + }, + { + "id": "t_dining_gen_87", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 20.26, + "time": 59.23, + "distance": 1563.62, + "gen_feat_1": 489.36, + "gen_feat_2": 0.51222, + "gen_feat_3": 503.86 + } + }, + { + "id": "t_dining_gen_88", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 19.46, + "time": 61.2, + "distance": 1588.14, + "gen_feat_1": 488.89, + "gen_feat_2": 0.496175, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_dining_gen_89", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 19.79, + "time": 58.63, + "distance": 1622.85, + "gen_feat_1": 512.62, + "gen_feat_2": 0.485995, + "gen_feat_3": 487.83 + } + }, + { + "id": "t_dining_gen_90", + "task_id": "t_dining", + "provider_id": "p_gen_2", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_2)", + "features": { + "cost": 19.48, + "time": 58.69, + "distance": 1640.49, + "gen_feat_1": 511.37, + "gen_feat_2": 0.494218, + "gen_feat_3": 505.83 + } + }, + { + "id": "t_dining_gen_91", + "task_id": "t_dining", + "provider_id": "p_gen_3", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_3)", + "features": { + "cost": 19.58, + "time": 58.72, + "distance": 1630.9, + "gen_feat_1": 505.33, + "gen_feat_2": 0.485446, + "gen_feat_3": 496.64 + } + }, + { + "id": "t_dining_gen_92", + "task_id": "t_dining", + "provider_id": "p_gen_4", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_4)", + "features": { + "cost": 20.04, + "time": 59.56, + "distance": 1559.07, + "gen_feat_1": 491.21, + "gen_feat_2": 0.509726, + "gen_feat_3": 514.19 + } + }, + { + "id": "t_dining_gen_93", + "task_id": "t_dining", + "provider_id": "p_gen_5", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_5)", + "features": { + "cost": 19.84, + "time": 60.45, + "distance": 1596.68, + "gen_feat_1": 493.98, + "gen_feat_2": 0.489239, + "gen_feat_3": 493.56 + } + }, + { + "id": "t_dining_gen_94", + "task_id": "t_dining", + "provider_id": "p_rest_autre_saison", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_rest_autre_saison)", + "features": { + "cost": 19.56, + "time": 59.95, + "distance": 1630.28, + "gen_feat_1": 488.49, + "gen_feat_2": 0.505218, + "gen_feat_3": 491.42 + } + }, + { + "id": "t_dining_gen_95", + "task_id": "t_dining", + "provider_id": "p_cinema_banque_scotia", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.97, + "time": 59.51, + "distance": 1593.3, + "gen_feat_1": 488.66, + "gen_feat_2": 0.490214, + "gen_feat_3": 504.25 + } + }, + { + "id": "t_dining_gen_96", + "task_id": "t_dining", + "provider_id": "p_seven_night_club", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_seven_night_club)", + "features": { + "cost": 19.85, + "time": 58.35, + "distance": 1552.26, + "gen_feat_1": 503.49, + "gen_feat_2": 0.48523, + "gen_feat_3": 504.39 + } + }, + { + "id": "t_dining_gen_97", + "task_id": "t_dining", + "provider_id": "p_local_shopping", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_local_shopping)", + "features": { + "cost": 20.51, + "time": 59.5, + "distance": 1634.44, + "gen_feat_1": 497.31, + "gen_feat_2": 0.5107, + "gen_feat_3": 507.86 + } + }, + { + "id": "t_dining_gen_98", + "task_id": "t_dining", + "provider_id": "p_gen_1", + "name": "Dinner at Restaurant L’Autre Saison (Gen p_gen_1)", + "features": { + "cost": 20.5, + "time": 61.17, + "distance": 1593.89, + "gen_feat_1": 510.31, + "gen_feat_2": 0.50078, + "gen_feat_3": 494.95 + } + }, + { + "id": "t_shopping_gen_2", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.95, + "time": 44.3, + "distance": 1198.71, + "gen_feat_1": 508.4, + "gen_feat_2": 0.485625, + "gen_feat_3": 507.99 + } + }, + { + "id": "t_shopping_gen_3", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.5, + "time": 44.18, + "distance": 1196.21, + "gen_feat_1": 485.72, + "gen_feat_2": 0.488455, + "gen_feat_3": 489.7 + } + }, + { + "id": "t_shopping_gen_4", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.78, + "time": 44.9, + "distance": 1179.12, + "gen_feat_1": 503.26, + "gen_feat_2": 0.498291, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_shopping_gen_5", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.51, + "time": 44.53, + "distance": 1216.23, + "gen_feat_1": 510.8, + "gen_feat_2": 0.507066, + "gen_feat_3": 504.03 + } + }, + { + "id": "t_shopping_gen_6", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.18, + "time": 44.06, + "distance": 1199.34, + "gen_feat_1": 501.17, + "gen_feat_2": 0.493458, + "gen_feat_3": 510.83 + } + }, + { + "id": "t_shopping_gen_7", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.59, + "time": 45.0, + "distance": 1183.14, + "gen_feat_1": 501.56, + "gen_feat_2": 0.496232, + "gen_feat_3": 496.33 + } + }, + { + "id": "t_shopping_gen_8", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.45, + "time": 43.75, + "distance": 1196.19, + "gen_feat_1": 488.54, + "gen_feat_2": 0.508864, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_9", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.29, + "time": 45.49, + "distance": 1235.6, + "gen_feat_1": 505.19, + "gen_feat_2": 0.486447, + "gen_feat_3": 505.3 + } + }, + { + "id": "t_shopping_gen_10", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.2, + "time": 44.86, + "distance": 1227.31, + "gen_feat_1": 487.19, + "gen_feat_2": 0.512416, + "gen_feat_3": 499.73 + } + }, + { + "id": "t_shopping_gen_11", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.86, + "time": 44.51, + "distance": 1227.77, + "gen_feat_1": 488.24, + "gen_feat_2": 0.510589, + "gen_feat_3": 510.74 + } + }, + { + "id": "t_shopping_gen_12", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.87, + "time": 44.69, + "distance": 1170.61, + "gen_feat_1": 503.79, + "gen_feat_2": 0.487994, + "gen_feat_3": 485.28 + } + }, + { + "id": "t_shopping_gen_13", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.87, + "time": 46.21, + "distance": 1228.85, + "gen_feat_1": 488.6, + "gen_feat_2": 0.499239, + "gen_feat_3": 503.2 + } + }, + { + "id": "t_shopping_gen_14", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.47, + "time": 44.09, + "distance": 1191.47, + "gen_feat_1": 510.69, + "gen_feat_2": 0.500607, + "gen_feat_3": 501.94 + } + }, + { + "id": "t_shopping_gen_15", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.91, + "time": 44.79, + "distance": 1194.44, + "gen_feat_1": 493.04, + "gen_feat_2": 0.493381, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_16", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.74, + "time": 45.76, + "distance": 1214.32, + "gen_feat_1": 508.04, + "gen_feat_2": 0.505849, + "gen_feat_3": 514.42 + } + }, + { + "id": "t_shopping_gen_17", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.56, + "time": 44.53, + "distance": 1186.46, + "gen_feat_1": 497.1, + "gen_feat_2": 0.507483, + "gen_feat_3": 487.33 + } + }, + { + "id": "t_shopping_gen_18", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.3, + "time": 46.02, + "distance": 1191.93, + "gen_feat_1": 502.5, + "gen_feat_2": 0.489832, + "gen_feat_3": 505.79 + } + }, + { + "id": "t_shopping_gen_19", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.29, + "time": 44.76, + "distance": 1178.65, + "gen_feat_1": 486.31, + "gen_feat_2": 0.501927, + "gen_feat_3": 510.24 + } + }, + { + "id": "t_shopping_gen_20", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.59, + "time": 45.62, + "distance": 1234.59, + "gen_feat_1": 508.23, + "gen_feat_2": 0.488622, + "gen_feat_3": 505.15 + } + }, + { + "id": "t_shopping_gen_21", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.41, + "time": 44.06, + "distance": 1185.1, + "gen_feat_1": 498.37, + "gen_feat_2": 0.491076, + "gen_feat_3": 502.07 + } + }, + { + "id": "t_shopping_gen_22", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.07, + "time": 45.23, + "distance": 1172.35, + "gen_feat_1": 489.15, + "gen_feat_2": 0.487341, + "gen_feat_3": 502.22 + } + }, + { + "id": "t_shopping_gen_23", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.07, + "time": 44.11, + "distance": 1228.63, + "gen_feat_1": 489.68, + "gen_feat_2": 0.497214, + "gen_feat_3": 510.3 + } + }, + { + "id": "t_shopping_gen_24", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.79, + "time": 45.29, + "distance": 1211.47, + "gen_feat_1": 513.99, + "gen_feat_2": 0.511272, + "gen_feat_3": 512.18 + } + }, + { + "id": "t_shopping_gen_25", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.49, + "time": 45.68, + "distance": 1197.16, + "gen_feat_1": 504.19, + "gen_feat_2": 0.507954, + "gen_feat_3": 509.7 + } + }, + { + "id": "t_shopping_gen_26", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.61, + "time": 45.73, + "distance": 1191.91, + "gen_feat_1": 499.13, + "gen_feat_2": 0.502797, + "gen_feat_3": 486.18 + } + }, + { + "id": "t_shopping_gen_27", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.64, + "time": 45.28, + "distance": 1176.71, + "gen_feat_1": 505.64, + "gen_feat_2": 0.491227, + "gen_feat_3": 508.35 + } + }, + { + "id": "t_shopping_gen_28", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.87, + "time": 45.0, + "distance": 1216.17, + "gen_feat_1": 500.61, + "gen_feat_2": 0.512609, + "gen_feat_3": 509.87 + } + }, + { + "id": "t_shopping_gen_29", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.37, + "time": 44.26, + "distance": 1180.24, + "gen_feat_1": 487.72, + "gen_feat_2": 0.485295, + "gen_feat_3": 487.2 + } + }, + { + "id": "t_shopping_gen_30", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.65, + "time": 44.57, + "distance": 1197.12, + "gen_feat_1": 500.2, + "gen_feat_2": 0.506494, + "gen_feat_3": 511.02 + } + }, + { + "id": "t_shopping_gen_31", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.54, + "time": 43.79, + "distance": 1190.28, + "gen_feat_1": 501.09, + "gen_feat_2": 0.496883, + "gen_feat_3": 504.0 + } + }, + { + "id": "t_shopping_gen_32", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.4, + "time": 44.15, + "distance": 1210.36, + "gen_feat_1": 506.65, + "gen_feat_2": 0.494619, + "gen_feat_3": 489.54 + } + }, + { + "id": "t_shopping_gen_33", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.78, + "time": 44.05, + "distance": 1224.7, + "gen_feat_1": 505.11, + "gen_feat_2": 0.497586, + "gen_feat_3": 502.56 + } + }, + { + "id": "t_shopping_gen_34", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.93, + "time": 45.15, + "distance": 1219.85, + "gen_feat_1": 498.34, + "gen_feat_2": 0.488983, + "gen_feat_3": 494.13 + } + }, + { + "id": "t_shopping_gen_35", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.82, + "time": 44.55, + "distance": 1224.73, + "gen_feat_1": 511.51, + "gen_feat_2": 0.504196, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_shopping_gen_36", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.86, + "time": 45.5, + "distance": 1196.08, + "gen_feat_1": 495.33, + "gen_feat_2": 0.498326, + "gen_feat_3": 486.34 + } + }, + { + "id": "t_shopping_gen_37", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.59, + "time": 44.26, + "distance": 1203.59, + "gen_feat_1": 496.81, + "gen_feat_2": 0.510331, + "gen_feat_3": 506.27 + } + }, + { + "id": "t_shopping_gen_38", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.92, + "time": 45.08, + "distance": 1203.94, + "gen_feat_1": 500.75, + "gen_feat_2": 0.49117, + "gen_feat_3": 491.78 + } + }, + { + "id": "t_shopping_gen_39", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.31, + "time": 46.16, + "distance": 1182.79, + "gen_feat_1": 497.1, + "gen_feat_2": 0.497946, + "gen_feat_3": 512.02 + } + }, + { + "id": "t_shopping_gen_40", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.54, + "time": 44.22, + "distance": 1217.58, + "gen_feat_1": 514.19, + "gen_feat_2": 0.507653, + "gen_feat_3": 502.34 + } + }, + { + "id": "t_shopping_gen_41", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.64, + "time": 44.32, + "distance": 1196.64, + "gen_feat_1": 510.6, + "gen_feat_2": 0.510227, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_42", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.93, + "time": 46.08, + "distance": 1215.22, + "gen_feat_1": 509.33, + "gen_feat_2": 0.489128, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_shopping_gen_43", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.94, + "time": 46.06, + "distance": 1197.83, + "gen_feat_1": 494.23, + "gen_feat_2": 0.491429, + "gen_feat_3": 512.77 + } + }, + { + "id": "t_shopping_gen_44", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.62, + "time": 44.6, + "distance": 1228.92, + "gen_feat_1": 503.07, + "gen_feat_2": 0.497061, + "gen_feat_3": 508.73 + } + }, + { + "id": "t_shopping_gen_45", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.54, + "time": 45.8, + "distance": 1230.3, + "gen_feat_1": 498.44, + "gen_feat_2": 0.491182, + "gen_feat_3": 510.12 + } + }, + { + "id": "t_shopping_gen_46", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.21, + "time": 44.28, + "distance": 1216.64, + "gen_feat_1": 488.95, + "gen_feat_2": 0.485686, + "gen_feat_3": 513.45 + } + }, + { + "id": "t_shopping_gen_47", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.4, + "time": 44.8, + "distance": 1210.54, + "gen_feat_1": 488.83, + "gen_feat_2": 0.508023, + "gen_feat_3": 485.22 + } + }, + { + "id": "t_shopping_gen_48", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.69, + "time": 44.94, + "distance": 1204.74, + "gen_feat_1": 504.02, + "gen_feat_2": 0.485166, + "gen_feat_3": 509.28 + } + }, + { + "id": "t_shopping_gen_49", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.63, + "time": 45.76, + "distance": 1234.29, + "gen_feat_1": 496.66, + "gen_feat_2": 0.510271, + "gen_feat_3": 488.57 + } + }, + { + "id": "t_shopping_gen_50", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.54, + "time": 44.91, + "distance": 1215.96, + "gen_feat_1": 509.77, + "gen_feat_2": 0.485673, + "gen_feat_3": 502.33 + } + }, + { + "id": "t_shopping_gen_51", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.48, + "time": 46.17, + "distance": 1186.08, + "gen_feat_1": 512.11, + "gen_feat_2": 0.491803, + "gen_feat_3": 503.47 + } + }, + { + "id": "t_shopping_gen_52", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.89, + "time": 44.45, + "distance": 1194.92, + "gen_feat_1": 500.1, + "gen_feat_2": 0.486916, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_shopping_gen_53", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.35, + "time": 44.61, + "distance": 1191.25, + "gen_feat_1": 503.61, + "gen_feat_2": 0.493221, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_shopping_gen_54", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.73, + "time": 45.54, + "distance": 1223.55, + "gen_feat_1": 494.27, + "gen_feat_2": 0.490001, + "gen_feat_3": 493.72 + } + }, + { + "id": "t_shopping_gen_55", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 44.24, + "distance": 1228.06, + "gen_feat_1": 497.25, + "gen_feat_2": 0.49955, + "gen_feat_3": 486.14 + } + }, + { + "id": "t_shopping_gen_56", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.69, + "time": 44.04, + "distance": 1224.5, + "gen_feat_1": 492.29, + "gen_feat_2": 0.500032, + "gen_feat_3": 491.23 + } + }, + { + "id": "t_shopping_gen_57", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.68, + "time": 46.32, + "distance": 1227.05, + "gen_feat_1": 510.63, + "gen_feat_2": 0.51217, + "gen_feat_3": 489.8 + } + }, + { + "id": "t_shopping_gen_58", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.13, + "time": 45.42, + "distance": 1231.38, + "gen_feat_1": 499.25, + "gen_feat_2": 0.502657, + "gen_feat_3": 488.16 + } + }, + { + "id": "t_shopping_gen_59", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.25, + "time": 45.04, + "distance": 1206.58, + "gen_feat_1": 488.66, + "gen_feat_2": 0.500622, + "gen_feat_3": 503.32 + } + }, + { + "id": "t_shopping_gen_60", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.33, + "time": 46.0, + "distance": 1170.11, + "gen_feat_1": 511.4, + "gen_feat_2": 0.49549, + "gen_feat_3": 503.71 + } + }, + { + "id": "t_shopping_gen_61", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.18, + "time": 46.1, + "distance": 1190.97, + "gen_feat_1": 498.6, + "gen_feat_2": 0.501812, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_62", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.24, + "time": 45.7, + "distance": 1164.26, + "gen_feat_1": 485.26, + "gen_feat_2": 0.49031, + "gen_feat_3": 487.45 + } + }, + { + "id": "t_shopping_gen_63", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.17, + "time": 45.97, + "distance": 1190.2, + "gen_feat_1": 511.28, + "gen_feat_2": 0.51432, + "gen_feat_3": 513.58 + } + }, + { + "id": "t_shopping_gen_64", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.73, + "time": 44.03, + "distance": 1178.97, + "gen_feat_1": 487.49, + "gen_feat_2": 0.508632, + "gen_feat_3": 500.21 + } + }, + { + "id": "t_shopping_gen_65", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.67, + "time": 43.83, + "distance": 1176.27, + "gen_feat_1": 512.03, + "gen_feat_2": 0.49815, + "gen_feat_3": 501.03 + } + }, + { + "id": "t_shopping_gen_66", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.26, + "time": 44.73, + "distance": 1220.07, + "gen_feat_1": 504.64, + "gen_feat_2": 0.502789, + "gen_feat_3": 505.95 + } + }, + { + "id": "t_shopping_gen_67", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 19.81, + "time": 44.73, + "distance": 1180.99, + "gen_feat_1": 491.13, + "gen_feat_2": 0.488945, + "gen_feat_3": 487.4 + } + }, + { + "id": "t_shopping_gen_68", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.86, + "time": 43.67, + "distance": 1232.56, + "gen_feat_1": 512.67, + "gen_feat_2": 0.491258, + "gen_feat_3": 495.53 + } + }, + { + "id": "t_shopping_gen_69", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.0, + "time": 45.32, + "distance": 1179.79, + "gen_feat_1": 504.7, + "gen_feat_2": 0.501825, + "gen_feat_3": 494.35 + } + }, + { + "id": "t_shopping_gen_70", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.08, + "time": 45.99, + "distance": 1206.39, + "gen_feat_1": 497.84, + "gen_feat_2": 0.509326, + "gen_feat_3": 508.37 + } + }, + { + "id": "t_shopping_gen_71", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.89, + "time": 44.23, + "distance": 1211.83, + "gen_feat_1": 489.02, + "gen_feat_2": 0.504569, + "gen_feat_3": 486.74 + } + }, + { + "id": "t_shopping_gen_72", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.25, + "time": 43.89, + "distance": 1218.83, + "gen_feat_1": 514.57, + "gen_feat_2": 0.487312, + "gen_feat_3": 491.96 + } + }, + { + "id": "t_shopping_gen_73", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 20.41, + "time": 45.64, + "distance": 1171.76, + "gen_feat_1": 499.58, + "gen_feat_2": 0.499353, + "gen_feat_3": 501.9 + } + }, + { + "id": "t_shopping_gen_74", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.51, + "time": 45.18, + "distance": 1235.16, + "gen_feat_1": 491.35, + "gen_feat_2": 0.488032, + "gen_feat_3": 508.76 + } + }, + { + "id": "t_shopping_gen_75", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 20.45, + "time": 45.29, + "distance": 1185.87, + "gen_feat_1": 506.16, + "gen_feat_2": 0.494622, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_shopping_gen_76", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.11, + "time": 44.39, + "distance": 1222.53, + "gen_feat_1": 507.53, + "gen_feat_2": 0.505002, + "gen_feat_3": 503.01 + } + }, + { + "id": "t_shopping_gen_77", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.93, + "time": 46.13, + "distance": 1210.75, + "gen_feat_1": 506.27, + "gen_feat_2": 0.505682, + "gen_feat_3": 500.78 + } + }, + { + "id": "t_shopping_gen_78", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.16, + "time": 46.07, + "distance": 1210.7, + "gen_feat_1": 508.56, + "gen_feat_2": 0.487189, + "gen_feat_3": 504.12 + } + }, + { + "id": "t_shopping_gen_79", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.03, + "time": 45.66, + "distance": 1190.96, + "gen_feat_1": 489.72, + "gen_feat_2": 0.488214, + "gen_feat_3": 510.57 + } + }, + { + "id": "t_shopping_gen_80", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.77, + "time": 45.73, + "distance": 1226.46, + "gen_feat_1": 498.85, + "gen_feat_2": 0.50612, + "gen_feat_3": 508.83 + } + }, + { + "id": "t_shopping_gen_81", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.19, + "time": 44.4, + "distance": 1207.41, + "gen_feat_1": 512.69, + "gen_feat_2": 0.49773, + "gen_feat_3": 499.57 + } + }, + { + "id": "t_shopping_gen_82", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.91, + "time": 45.81, + "distance": 1232.14, + "gen_feat_1": 501.37, + "gen_feat_2": 0.501413, + "gen_feat_3": 509.02 + } + }, + { + "id": "t_shopping_gen_83", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 20.46, + "time": 45.7, + "distance": 1201.06, + "gen_feat_1": 507.37, + "gen_feat_2": 0.512514, + "gen_feat_3": 495.31 + } + }, + { + "id": "t_shopping_gen_84", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.46, + "time": 45.7, + "distance": 1176.63, + "gen_feat_1": 500.57, + "gen_feat_2": 0.512907, + "gen_feat_3": 496.18 + } + }, + { + "id": "t_shopping_gen_85", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.3, + "time": 44.77, + "distance": 1227.54, + "gen_feat_1": 488.72, + "gen_feat_2": 0.491267, + "gen_feat_3": 504.72 + } + }, + { + "id": "t_shopping_gen_86", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 19.53, + "time": 44.82, + "distance": 1227.19, + "gen_feat_1": 495.19, + "gen_feat_2": 0.506807, + "gen_feat_3": 489.97 + } + }, + { + "id": "t_shopping_gen_87", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 19.76, + "time": 45.19, + "distance": 1197.27, + "gen_feat_1": 492.23, + "gen_feat_2": 0.502276, + "gen_feat_3": 497.83 + } + }, + { + "id": "t_shopping_gen_88", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 19.51, + "time": 46.32, + "distance": 1202.27, + "gen_feat_1": 514.83, + "gen_feat_2": 0.500008, + "gen_feat_3": 494.37 + } + }, + { + "id": "t_shopping_gen_89", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 20.31, + "time": 45.09, + "distance": 1196.05, + "gen_feat_1": 488.52, + "gen_feat_2": 0.501783, + "gen_feat_3": 493.65 + } + }, + { + "id": "t_shopping_gen_90", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 20.15, + "time": 45.09, + "distance": 1187.36, + "gen_feat_1": 510.87, + "gen_feat_2": 0.48952, + "gen_feat_3": 487.44 + } + }, + { + "id": "t_shopping_gen_91", + "task_id": "t_shopping", + "provider_id": "p_gen_1", + "name": "Shopping at a nearby venue (Gen p_gen_1)", + "features": { + "cost": 19.98, + "time": 44.28, + "distance": 1230.46, + "gen_feat_1": 494.85, + "gen_feat_2": 0.49072, + "gen_feat_3": 507.33 + } + }, + { + "id": "t_shopping_gen_92", + "task_id": "t_shopping", + "provider_id": "p_gen_2", + "name": "Shopping at a nearby venue (Gen p_gen_2)", + "features": { + "cost": 19.46, + "time": 44.78, + "distance": 1190.65, + "gen_feat_1": 511.14, + "gen_feat_2": 0.491965, + "gen_feat_3": 510.07 + } + }, + { + "id": "t_shopping_gen_93", + "task_id": "t_shopping", + "provider_id": "p_gen_3", + "name": "Shopping at a nearby venue (Gen p_gen_3)", + "features": { + "cost": 19.89, + "time": 44.16, + "distance": 1232.76, + "gen_feat_1": 491.76, + "gen_feat_2": 0.49386, + "gen_feat_3": 489.99 + } + }, + { + "id": "t_shopping_gen_94", + "task_id": "t_shopping", + "provider_id": "p_gen_4", + "name": "Shopping at a nearby venue (Gen p_gen_4)", + "features": { + "cost": 20.09, + "time": 45.07, + "distance": 1187.9, + "gen_feat_1": 500.36, + "gen_feat_2": 0.505173, + "gen_feat_3": 512.28 + } + }, + { + "id": "t_shopping_gen_95", + "task_id": "t_shopping", + "provider_id": "p_gen_5", + "name": "Shopping at a nearby venue (Gen p_gen_5)", + "features": { + "cost": 20.29, + "time": 44.73, + "distance": 1224.17, + "gen_feat_1": 507.58, + "gen_feat_2": 0.48708, + "gen_feat_3": 511.59 + } + }, + { + "id": "t_shopping_gen_96", + "task_id": "t_shopping", + "provider_id": "p_rest_autre_saison", + "name": "Shopping at a nearby venue (Gen p_rest_autre_saison)", + "features": { + "cost": 20.53, + "time": 43.89, + "distance": 1206.53, + "gen_feat_1": 493.71, + "gen_feat_2": 0.505153, + "gen_feat_3": 502.61 + } + }, + { + "id": "t_shopping_gen_97", + "task_id": "t_shopping", + "provider_id": "p_cinema_banque_scotia", + "name": "Shopping at a nearby venue (Gen p_cinema_banque_scotia)", + "features": { + "cost": 20.6, + "time": 45.25, + "distance": 1198.77, + "gen_feat_1": 499.74, + "gen_feat_2": 0.499805, + "gen_feat_3": 508.22 + } + }, + { + "id": "t_shopping_gen_98", + "task_id": "t_shopping", + "provider_id": "p_seven_night_club", + "name": "Shopping at a nearby venue (Gen p_seven_night_club)", + "features": { + "cost": 19.94, + "time": 45.61, + "distance": 1168.51, + "gen_feat_1": 491.6, + "gen_feat_2": 0.511011, + "gen_feat_3": 491.45 + } + }, + { + "id": "t_shopping_gen_99", + "task_id": "t_shopping", + "provider_id": "p_local_shopping", + "name": "Shopping at a nearby venue (Gen p_local_shopping)", + "features": { + "cost": 19.76, + "time": 45.99, + "distance": 1192.67, + "gen_feat_1": 500.07, + "gen_feat_2": 0.491787, + "gen_feat_3": 488.2 + } + }, + { + "id": "t_movie_gen_2", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.81, + "time": 138.02, + "distance": 1654.01, + "gen_feat_1": 503.91, + "gen_feat_2": 0.502664, + "gen_feat_3": 506.8 + } + }, + { + "id": "t_movie_gen_3", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.98, + "time": 133.32, + "distance": 1664.29, + "gen_feat_1": 491.47, + "gen_feat_2": 0.500325, + "gen_feat_3": 496.28 + } + }, + { + "id": "t_movie_gen_4", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.11, + "time": 136.06, + "distance": 1704.88, + "gen_feat_1": 505.19, + "gen_feat_2": 0.509953, + "gen_feat_3": 499.19 + } + }, + { + "id": "t_movie_gen_5", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.17, + "time": 136.4, + "distance": 1724.13, + "gen_feat_1": 511.77, + "gen_feat_2": 0.505076, + "gen_feat_3": 491.0 + } + }, + { + "id": "t_movie_gen_6", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.2, + "time": 137.15, + "distance": 1664.63, + "gen_feat_1": 514.48, + "gen_feat_2": 0.503771, + "gen_feat_3": 487.67 + } + }, + { + "id": "t_movie_gen_7", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.16, + "time": 135.61, + "distance": 1726.58, + "gen_feat_1": 493.34, + "gen_feat_2": 0.493128, + "gen_feat_3": 491.4 + } + }, + { + "id": "t_movie_gen_8", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.91, + "time": 135.69, + "distance": 1678.5, + "gen_feat_1": 493.49, + "gen_feat_2": 0.506584, + "gen_feat_3": 491.95 + } + }, + { + "id": "t_movie_gen_9", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.09, + "time": 132.47, + "distance": 1682.74, + "gen_feat_1": 513.37, + "gen_feat_2": 0.496243, + "gen_feat_3": 510.52 + } + }, + { + "id": "t_movie_gen_10", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.25, + "time": 134.94, + "distance": 1683.72, + "gen_feat_1": 493.66, + "gen_feat_2": 0.502149, + "gen_feat_3": 491.38 + } + }, + { + "id": "t_movie_gen_11", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 132.2, + "distance": 1677.4, + "gen_feat_1": 513.51, + "gen_feat_2": 0.512663, + "gen_feat_3": 496.77 + } + }, + { + "id": "t_movie_gen_12", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.02, + "time": 136.12, + "distance": 1683.25, + "gen_feat_1": 486.72, + "gen_feat_2": 0.48763, + "gen_feat_3": 498.97 + } + }, + { + "id": "t_movie_gen_13", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 131.91, + "distance": 1710.85, + "gen_feat_1": 493.33, + "gen_feat_2": 0.499006, + "gen_feat_3": 497.58 + } + }, + { + "id": "t_movie_gen_14", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.85, + "time": 137.69, + "distance": 1738.0, + "gen_feat_1": 501.65, + "gen_feat_2": 0.507629, + "gen_feat_3": 509.86 + } + }, + { + "id": "t_movie_gen_15", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.02, + "time": 133.61, + "distance": 1660.2, + "gen_feat_1": 512.64, + "gen_feat_2": 0.487548, + "gen_feat_3": 514.53 + } + }, + { + "id": "t_movie_gen_16", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.2, + "time": 132.6, + "distance": 1669.36, + "gen_feat_1": 490.54, + "gen_feat_2": 0.507088, + "gen_feat_3": 496.37 + } + }, + { + "id": "t_movie_gen_17", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.25, + "time": 138.2, + "distance": 1711.42, + "gen_feat_1": 497.15, + "gen_feat_2": 0.513509, + "gen_feat_3": 498.93 + } + }, + { + "id": "t_movie_gen_18", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.76, + "time": 136.31, + "distance": 1749.75, + "gen_feat_1": 514.83, + "gen_feat_2": 0.50335, + "gen_feat_3": 503.33 + } + }, + { + "id": "t_movie_gen_19", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 131.68, + "distance": 1656.52, + "gen_feat_1": 487.37, + "gen_feat_2": 0.493627, + "gen_feat_3": 508.19 + } + }, + { + "id": "t_movie_gen_20", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.9, + "time": 137.27, + "distance": 1709.53, + "gen_feat_1": 497.44, + "gen_feat_2": 0.486038, + "gen_feat_3": 502.32 + } + }, + { + "id": "t_movie_gen_21", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.83, + "time": 136.88, + "distance": 1708.94, + "gen_feat_1": 492.6, + "gen_feat_2": 0.496495, + "gen_feat_3": 490.83 + } + }, + { + "id": "t_movie_gen_22", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.12, + "time": 133.07, + "distance": 1711.62, + "gen_feat_1": 493.34, + "gen_feat_2": 0.499182, + "gen_feat_3": 499.28 + } + }, + { + "id": "t_movie_gen_23", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.12, + "time": 134.21, + "distance": 1736.25, + "gen_feat_1": 503.64, + "gen_feat_2": 0.5068, + "gen_feat_3": 489.21 + } + }, + { + "id": "t_movie_gen_24", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 132.64, + "distance": 1664.88, + "gen_feat_1": 510.09, + "gen_feat_2": 0.510289, + "gen_feat_3": 492.32 + } + }, + { + "id": "t_movie_gen_25", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.1, + "time": 137.12, + "distance": 1701.34, + "gen_feat_1": 501.06, + "gen_feat_2": 0.49893, + "gen_feat_3": 507.73 + } + }, + { + "id": "t_movie_gen_26", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 136.45, + "distance": 1678.04, + "gen_feat_1": 494.8, + "gen_feat_2": 0.485118, + "gen_feat_3": 508.86 + } + }, + { + "id": "t_movie_gen_27", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.83, + "time": 134.67, + "distance": 1694.92, + "gen_feat_1": 503.64, + "gen_feat_2": 0.511029, + "gen_feat_3": 505.48 + } + }, + { + "id": "t_movie_gen_28", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.96, + "time": 138.62, + "distance": 1659.13, + "gen_feat_1": 491.47, + "gen_feat_2": 0.511429, + "gen_feat_3": 500.08 + } + }, + { + "id": "t_movie_gen_29", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.76, + "time": 138.64, + "distance": 1697.07, + "gen_feat_1": 498.44, + "gen_feat_2": 0.509025, + "gen_feat_3": 498.72 + } + }, + { + "id": "t_movie_gen_30", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.39, + "distance": 1730.3, + "gen_feat_1": 510.02, + "gen_feat_2": 0.491101, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_31", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.28, + "time": 131.41, + "distance": 1685.65, + "gen_feat_1": 490.64, + "gen_feat_2": 0.485642, + "gen_feat_3": 489.05 + } + }, + { + "id": "t_movie_gen_32", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.93, + "time": 134.98, + "distance": 1695.11, + "gen_feat_1": 501.21, + "gen_feat_2": 0.50543, + "gen_feat_3": 499.51 + } + }, + { + "id": "t_movie_gen_33", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.87, + "time": 137.83, + "distance": 1715.38, + "gen_feat_1": 513.71, + "gen_feat_2": 0.493568, + "gen_feat_3": 514.01 + } + }, + { + "id": "t_movie_gen_34", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.81, + "time": 132.4, + "distance": 1663.09, + "gen_feat_1": 506.91, + "gen_feat_2": 0.510638, + "gen_feat_3": 501.83 + } + }, + { + "id": "t_movie_gen_35", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.24, + "time": 136.79, + "distance": 1694.27, + "gen_feat_1": 510.84, + "gen_feat_2": 0.507452, + "gen_feat_3": 504.73 + } + }, + { + "id": "t_movie_gen_36", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.16, + "time": 136.15, + "distance": 1670.24, + "gen_feat_1": 502.99, + "gen_feat_2": 0.495856, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_37", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.3, + "time": 136.48, + "distance": 1719.06, + "gen_feat_1": 512.77, + "gen_feat_2": 0.488773, + "gen_feat_3": 505.19 + } + }, + { + "id": "t_movie_gen_38", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.89, + "time": 137.8, + "distance": 1682.43, + "gen_feat_1": 514.67, + "gen_feat_2": 0.508214, + "gen_feat_3": 504.71 + } + }, + { + "id": "t_movie_gen_39", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.88, + "time": 136.94, + "distance": 1652.85, + "gen_feat_1": 499.19, + "gen_feat_2": 0.500729, + "gen_feat_3": 511.08 + } + }, + { + "id": "t_movie_gen_40", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.75, + "time": 136.81, + "distance": 1673.83, + "gen_feat_1": 510.5, + "gen_feat_2": 0.496266, + "gen_feat_3": 512.35 + } + }, + { + "id": "t_movie_gen_41", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.84, + "time": 133.13, + "distance": 1698.79, + "gen_feat_1": 504.79, + "gen_feat_2": 0.491761, + "gen_feat_3": 489.88 + } + }, + { + "id": "t_movie_gen_42", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.79, + "time": 132.71, + "distance": 1654.02, + "gen_feat_1": 488.54, + "gen_feat_2": 0.496646, + "gen_feat_3": 506.89 + } + }, + { + "id": "t_movie_gen_43", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.03, + "time": 135.73, + "distance": 1687.52, + "gen_feat_1": 489.12, + "gen_feat_2": 0.50799, + "gen_feat_3": 499.94 + } + }, + { + "id": "t_movie_gen_44", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.09, + "time": 138.68, + "distance": 1703.05, + "gen_feat_1": 510.12, + "gen_feat_2": 0.485551, + "gen_feat_3": 502.13 + } + }, + { + "id": "t_movie_gen_45", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.86, + "time": 133.42, + "distance": 1652.65, + "gen_feat_1": 488.6, + "gen_feat_2": 0.510397, + "gen_feat_3": 509.98 + } + }, + { + "id": "t_movie_gen_46", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.97, + "time": 131.94, + "distance": 1673.56, + "gen_feat_1": 486.56, + "gen_feat_2": 0.505523, + "gen_feat_3": 501.82 + } + }, + { + "id": "t_movie_gen_47", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.0, + "time": 133.55, + "distance": 1671.34, + "gen_feat_1": 488.32, + "gen_feat_2": 0.49915, + "gen_feat_3": 504.35 + } + }, + { + "id": "t_movie_gen_48", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.06, + "time": 138.36, + "distance": 1677.66, + "gen_feat_1": 497.58, + "gen_feat_2": 0.497849, + "gen_feat_3": 488.29 + } + }, + { + "id": "t_movie_gen_49", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 133.95, + "distance": 1742.48, + "gen_feat_1": 495.5, + "gen_feat_2": 0.511503, + "gen_feat_3": 491.31 + } + }, + { + "id": "t_movie_gen_50", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.77, + "time": 135.54, + "distance": 1710.41, + "gen_feat_1": 487.97, + "gen_feat_2": 0.508317, + "gen_feat_3": 490.49 + } + }, + { + "id": "t_movie_gen_51", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.77, + "time": 135.9, + "distance": 1664.29, + "gen_feat_1": 513.14, + "gen_feat_2": 0.507714, + "gen_feat_3": 487.99 + } + }, + { + "id": "t_movie_gen_52", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.74, + "time": 133.36, + "distance": 1679.04, + "gen_feat_1": 502.14, + "gen_feat_2": 0.489374, + "gen_feat_3": 501.0 + } + }, + { + "id": "t_movie_gen_53", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.75, + "time": 137.75, + "distance": 1727.9, + "gen_feat_1": 494.43, + "gen_feat_2": 0.492795, + "gen_feat_3": 507.56 + } + }, + { + "id": "t_movie_gen_54", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 137.23, + "distance": 1749.88, + "gen_feat_1": 493.13, + "gen_feat_2": 0.514964, + "gen_feat_3": 513.51 + } + }, + { + "id": "t_movie_gen_55", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.27, + "time": 131.7, + "distance": 1671.69, + "gen_feat_1": 491.71, + "gen_feat_2": 0.507637, + "gen_feat_3": 496.63 + } + }, + { + "id": "t_movie_gen_56", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.25, + "time": 133.82, + "distance": 1744.69, + "gen_feat_1": 513.96, + "gen_feat_2": 0.486719, + "gen_feat_3": 505.59 + } + }, + { + "id": "t_movie_gen_57", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.04, + "time": 134.99, + "distance": 1687.02, + "gen_feat_1": 495.73, + "gen_feat_2": 0.497053, + "gen_feat_3": 485.08 + } + }, + { + "id": "t_movie_gen_58", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.9, + "time": 134.0, + "distance": 1717.93, + "gen_feat_1": 498.58, + "gen_feat_2": 0.514512, + "gen_feat_3": 495.1 + } + }, + { + "id": "t_movie_gen_59", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 135.99, + "distance": 1669.61, + "gen_feat_1": 506.91, + "gen_feat_2": 0.486343, + "gen_feat_3": 513.29 + } + }, + { + "id": "t_movie_gen_60", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.95, + "time": 137.16, + "distance": 1727.65, + "gen_feat_1": 511.78, + "gen_feat_2": 0.498191, + "gen_feat_3": 495.09 + } + }, + { + "id": "t_movie_gen_61", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.06, + "time": 131.51, + "distance": 1688.72, + "gen_feat_1": 501.65, + "gen_feat_2": 0.503774, + "gen_feat_3": 494.98 + } + }, + { + "id": "t_movie_gen_62", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 134.94, + "distance": 1688.34, + "gen_feat_1": 486.17, + "gen_feat_2": 0.506252, + "gen_feat_3": 499.8 + } + }, + { + "id": "t_movie_gen_63", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.0, + "time": 132.52, + "distance": 1696.65, + "gen_feat_1": 514.69, + "gen_feat_2": 0.493209, + "gen_feat_3": 485.24 + } + }, + { + "id": "t_movie_gen_64", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.73, + "time": 131.33, + "distance": 1699.32, + "gen_feat_1": 494.73, + "gen_feat_2": 0.500638, + "gen_feat_3": 507.36 + } + }, + { + "id": "t_movie_gen_65", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.28, + "time": 135.57, + "distance": 1672.37, + "gen_feat_1": 512.61, + "gen_feat_2": 0.49003, + "gen_feat_3": 498.67 + } + }, + { + "id": "t_movie_gen_66", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.81, + "time": 133.8, + "distance": 1700.55, + "gen_feat_1": 512.0, + "gen_feat_2": 0.486179, + "gen_feat_3": 501.33 + } + }, + { + "id": "t_movie_gen_67", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.03, + "time": 131.77, + "distance": 1745.74, + "gen_feat_1": 503.3, + "gen_feat_2": 0.51441, + "gen_feat_3": 486.9 + } + }, + { + "id": "t_movie_gen_68", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.9, + "time": 137.31, + "distance": 1655.07, + "gen_feat_1": 485.6, + "gen_feat_2": 0.49856, + "gen_feat_3": 495.04 + } + }, + { + "id": "t_movie_gen_69", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 10.19, + "time": 137.9, + "distance": 1713.23, + "gen_feat_1": 510.23, + "gen_feat_2": 0.490473, + "gen_feat_3": 492.48 + } + }, + { + "id": "t_movie_gen_70", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.92, + "time": 137.74, + "distance": 1742.03, + "gen_feat_1": 497.94, + "gen_feat_2": 0.514756, + "gen_feat_3": 487.31 + } + }, + { + "id": "t_movie_gen_71", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.28, + "time": 134.06, + "distance": 1654.96, + "gen_feat_1": 510.56, + "gen_feat_2": 0.492021, + "gen_feat_3": 489.25 + } + }, + { + "id": "t_movie_gen_72", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.24, + "time": 135.82, + "distance": 1738.49, + "gen_feat_1": 500.42, + "gen_feat_2": 0.493135, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_73", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 134.69, + "distance": 1663.19, + "gen_feat_1": 491.2, + "gen_feat_2": 0.505794, + "gen_feat_3": 504.69 + } + }, + { + "id": "t_movie_gen_74", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.82, + "time": 132.56, + "distance": 1679.26, + "gen_feat_1": 497.39, + "gen_feat_2": 0.485217, + "gen_feat_3": 513.12 + } + }, + { + "id": "t_movie_gen_75", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 10.18, + "time": 134.95, + "distance": 1745.08, + "gen_feat_1": 491.08, + "gen_feat_2": 0.495277, + "gen_feat_3": 513.42 + } + }, + { + "id": "t_movie_gen_76", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.16, + "time": 138.62, + "distance": 1666.98, + "gen_feat_1": 501.07, + "gen_feat_2": 0.506814, + "gen_feat_3": 489.44 + } + }, + { + "id": "t_movie_gen_77", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 9.76, + "time": 130.95, + "distance": 1675.39, + "gen_feat_1": 513.23, + "gen_feat_2": 0.496512, + "gen_feat_3": 496.71 + } + }, + { + "id": "t_movie_gen_78", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.99, + "time": 132.12, + "distance": 1674.54, + "gen_feat_1": 495.99, + "gen_feat_2": 0.496439, + "gen_feat_3": 506.49 + } + }, + { + "id": "t_movie_gen_79", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 9.84, + "time": 132.9, + "distance": 1698.58, + "gen_feat_1": 486.83, + "gen_feat_2": 0.487385, + "gen_feat_3": 489.3 + } + }, + { + "id": "t_movie_gen_80", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.03, + "time": 135.25, + "distance": 1703.48, + "gen_feat_1": 497.71, + "gen_feat_2": 0.506091, + "gen_feat_3": 509.17 + } + }, + { + "id": "t_movie_gen_81", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.08, + "time": 138.34, + "distance": 1706.78, + "gen_feat_1": 501.18, + "gen_feat_2": 0.503416, + "gen_feat_3": 493.11 + } + }, + { + "id": "t_movie_gen_82", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 9.95, + "time": 132.28, + "distance": 1658.35, + "gen_feat_1": 488.13, + "gen_feat_2": 0.514958, + "gen_feat_3": 513.35 + } + }, + { + "id": "t_movie_gen_83", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 10.06, + "time": 135.04, + "distance": 1663.79, + "gen_feat_1": 495.07, + "gen_feat_2": 0.489223, + "gen_feat_3": 514.52 + } + }, + { + "id": "t_movie_gen_84", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.76, + "time": 137.41, + "distance": 1703.65, + "gen_feat_1": 504.9, + "gen_feat_2": 0.503529, + "gen_feat_3": 500.87 + } + }, + { + "id": "t_movie_gen_85", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 10.08, + "time": 135.55, + "distance": 1691.79, + "gen_feat_1": 503.38, + "gen_feat_2": 0.5004, + "gen_feat_3": 510.63 + } + }, + { + "id": "t_movie_gen_86", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.24, + "time": 133.11, + "distance": 1689.53, + "gen_feat_1": 509.79, + "gen_feat_2": 0.49881, + "gen_feat_3": 488.86 + } + }, + { + "id": "t_movie_gen_87", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.89, + "time": 137.15, + "distance": 1698.06, + "gen_feat_1": 503.82, + "gen_feat_2": 0.50464, + "gen_feat_3": 512.29 + } + }, + { + "id": "t_movie_gen_88", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.13, + "time": 131.18, + "distance": 1660.59, + "gen_feat_1": 492.85, + "gen_feat_2": 0.514114, + "gen_feat_3": 513.82 + } + }, + { + "id": "t_movie_gen_89", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 9.87, + "time": 135.02, + "distance": 1741.57, + "gen_feat_1": 501.92, + "gen_feat_2": 0.508398, + "gen_feat_3": 493.5 + } + }, + { + "id": "t_movie_gen_90", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 10.28, + "time": 137.35, + "distance": 1718.09, + "gen_feat_1": 488.68, + "gen_feat_2": 0.49537, + "gen_feat_3": 493.95 + } + }, + { + "id": "t_movie_gen_91", + "task_id": "t_movie", + "provider_id": "p_local_shopping", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_local_shopping)", + "features": { + "cost": 10.04, + "time": 137.3, + "distance": 1693.34, + "gen_feat_1": 493.19, + "gen_feat_2": 0.495672, + "gen_feat_3": 488.25 + } + }, + { + "id": "t_movie_gen_92", + "task_id": "t_movie", + "provider_id": "p_gen_1", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_1)", + "features": { + "cost": 9.83, + "time": 137.58, + "distance": 1744.3, + "gen_feat_1": 491.56, + "gen_feat_2": 0.498387, + "gen_feat_3": 511.69 + } + }, + { + "id": "t_movie_gen_93", + "task_id": "t_movie", + "provider_id": "p_gen_2", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_2)", + "features": { + "cost": 9.91, + "time": 133.34, + "distance": 1702.93, + "gen_feat_1": 488.01, + "gen_feat_2": 0.502779, + "gen_feat_3": 491.18 + } + }, + { + "id": "t_movie_gen_94", + "task_id": "t_movie", + "provider_id": "p_gen_3", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_3)", + "features": { + "cost": 9.95, + "time": 134.1, + "distance": 1680.7, + "gen_feat_1": 497.7, + "gen_feat_2": 0.497436, + "gen_feat_3": 502.47 + } + }, + { + "id": "t_movie_gen_95", + "task_id": "t_movie", + "provider_id": "p_gen_4", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_4)", + "features": { + "cost": 10.19, + "time": 136.67, + "distance": 1705.0, + "gen_feat_1": 488.28, + "gen_feat_2": 0.487878, + "gen_feat_3": 495.8 + } + }, + { + "id": "t_movie_gen_96", + "task_id": "t_movie", + "provider_id": "p_gen_5", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_gen_5)", + "features": { + "cost": 9.9, + "time": 134.07, + "distance": 1659.49, + "gen_feat_1": 492.47, + "gen_feat_2": 0.492451, + "gen_feat_3": 511.78 + } + }, + { + "id": "t_movie_gen_97", + "task_id": "t_movie", + "provider_id": "p_rest_autre_saison", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_rest_autre_saison)", + "features": { + "cost": 10.21, + "time": 134.31, + "distance": 1734.61, + "gen_feat_1": 493.2, + "gen_feat_2": 0.488477, + "gen_feat_3": 503.93 + } + }, + { + "id": "t_movie_gen_98", + "task_id": "t_movie", + "provider_id": "p_cinema_banque_scotia", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_cinema_banque_scotia)", + "features": { + "cost": 10.19, + "time": 135.67, + "distance": 1729.26, + "gen_feat_1": 489.64, + "gen_feat_2": 0.491387, + "gen_feat_3": 506.86 + } + }, + { + "id": "t_movie_gen_99", + "task_id": "t_movie", + "provider_id": "p_seven_night_club", + "name": "Watch movie 'The Help' at Cinema Banque Scotia Montreal (Gen p_seven_night_club)", + "features": { + "cost": 9.79, + "time": 133.64, + "distance": 1673.71, + "gen_feat_1": 505.04, + "gen_feat_2": 0.505422, + "gen_feat_3": 513.37 + } + } + ], + "composition": { + "type": "STRUCTURED", + "root": { + "id": "n_root", + "kind": "SEQ", + "children": [ + { + "id": "n_dining", + "kind": "TASK", + "task_id": "t_dining" + }, + { + "id": "n_shopping", + "kind": "TASK", + "task_id": "t_shopping" + }, + { + "id": "n_movie", + "kind": "TASK", + "task_id": "t_movie" + } + ] + } + }, + "aggregation_policies": { + "cost": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "time": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "distance": { + "neutral": 0, + "compose": { + "seq": { + "fn": "MAX" + }, + "and": { + "fn": "MAX" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_1": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + }, + "gen_feat_2": { + "neutral": 1, + "compose": { + "seq": { + "fn": "PRODUCT" + }, + "and": { + "fn": "PRODUCT" + }, + "loop": { + "fn": "SCALED_PRODUCT" + } + } + }, + "gen_feat_3": { + "neutral": 0, + "compose": { + "seq": { + "fn": "SUM" + }, + "and": { + "fn": "SUM" + }, + "loop": { + "fn": "SCALED_SUM" + } + } + } + }, + "constraints": [ + { + "id": "c_within_2km", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "distance", + "op": "<=", + "value": 2000, + "hard": false + }, + { + "id": "c_time_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "time", + "op": "<=", + "value": 240, + "hard": false + }, + { + "id": "c_cost_budget", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 100, + "hard": false + }, + { + "id": "gen_c_global_cost_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "GLOBAL", + "attribute_id": "cost", + "op": "<=", + "value": 50.07, + "hard": false + }, + { + "id": "gen_c_local_t_dining_time_1", + "kind": "ATTRIBUTE_BOUND", + "scope": "LOCAL", + "tasks": [ + "t_dining" + ], + "attribute_id": "time", + "op": "<=", + "value": 59.79, + "hard": false + }, + { + "id": "gen_c_dep_same_1", + "kind": "DEPENDENCY", + "type": "SAME_PROVIDER", + "tasks": [ + "t_dining", + "t_shopping" + ], + "hard": false + }, + { + "id": "gen_c_dep_diff_1", + "kind": "DEPENDENCY", + "type": "DIFFERENT_PROVIDER", + "tasks": [ + "t_dining", + "t_movie" + ], + "hard": false + } + ], + "objective": { + "type": "MULTI", + "targets": [ + "cost", + "distance", + "gen_feat_1" + ], + "weights": { + "cost": 0.34, + "distance": 0.33, + "gen_feat_1": 0.33 + }, + "weights_sum_to_one": true + } +} \ No newline at end of file diff --git a/experimentation/report.md b/experimentation/report.md new file mode 100644 index 0000000..4ee6589 --- /dev/null +++ b/experimentation/report.md @@ -0,0 +1,5181 @@ +# Experiment Report + +**Generated**: 2026-02-12 12:04:10 + +**Total**: 48 | **Passed**: 46 | **Failed**: 2 + +![Progress](https://geps.dev/progress/95?dangerColor=d9534f&warningColor=f0ad4e&successColor=5cb85c) + +## Summary + +| Instance | Obj | Soft | MiniZinc | RandomSearch | ManyHeuristic | Binding Match | Binding Space Size | Result | +|---|---|---|---|---|---|---|---|---| +| benatallah2002-selfserv-tra... | MANY | False | 🔴 422 | 🔴 422 | 🟢 200 | - | - | ❌ FAIL (MANY NoSol) | +| benatallah2002-selfserv-tra... | MANY | True | 🔴 422 | 🔴 422 | 🟢 200 | - | - | ✅ PASS (MZN/RS Reject, MANY Solve) | +| benatallah2002-selfserv-tra... | MONO | False | 🟢 200 | 🟢 200 | 🔴 422 | ⚠️ DIFF (HEUR) | 1000000 | ✅ PASS (Both Solved) | +| benatallah2002-selfserv-tra... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1000000 | ✅ PASS (MZN Reject, RS Solve) | +| benatallah2002-selfserv-tra... | MONO | False | 🟢 200 | 🟢 200 | 🔴 422 | ⚠️ RS NoSol | 1000000 | ✅ PASS (MZN Solved, RS NoSol) | +| benatallah2002-selfserv-tra... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1000000 | ✅ PASS (MZN Reject, RS Solve) | +| benatallah2002-selfserv-tra... | MULTI | False | 🔴 422 | 🔴 422 | 🔴 422 | - | - | ✅ PASS (All Rejected) | +| benatallah2002-selfserv-tra... | MULTI | True | 🔴 422 | 🔴 422 | 🔴 422 | - | - | ✅ PASS (All Rejected) | +| bultan2003-warehouse-exampl... | MANY | False | 🔴 422 | 🔴 422 | 🟢 200 | - | - | ✅ PASS (MZN/RS Reject, MANY Solve) | +| bultan2003-warehouse-exampl... | MANY | True | 🔴 422 | 🔴 422 | 🟢 200 | - | - | ✅ PASS (MZN/RS Reject, MANY Solve) | +| bultan2003-warehouse-exampl... | MONO | False | 🟢 200 | 🟢 200 | 🔴 422 | ⚠️ MZN NoSol | 1048576 | ✅ PASS (Both Solved) | +| bultan2003-warehouse-exampl... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1048576 | ✅ PASS (MZN Reject, RS Solve) | +| bultan2003-warehouse-exampl... | MONO | False | 🟢 200 | 🟢 200 | 🔴 422 | ⚠️ MZN NoSol | 1048576 | ✅ PASS (Both Solved) | +| bultan2003-warehouse-exampl... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1048576 | ✅ PASS (MZN Reject, RS Solve) | +| bultan2003-warehouse-exampl... | MULTI | False | 🔴 422 | 🔴 422 | 🔴 422 | - | - | ✅ PASS (All Rejected) | +| bultan2003-warehouse-exampl... | MULTI | True | 🔴 422 | 🔴 422 | 🔴 422 | - | - | ✅ PASS (All Rejected) | +| cremaschi2018-textbook-acce... | MANY | False | 🔴 422 | 🔴 422 | 🟢 200 | - | - | ✅ PASS (MZN/RS Reject, MANY Solve) | +| cremaschi2018-textbook-acce... | MANY | True | 🔴 422 | 🔴 422 | 🟢 200 | - | - | ✅ PASS (MZN/RS Reject, MANY Solve) | +| cremaschi2018-textbook-acce... | MONO | False | 🟢 200 | 🟢 200 | 🔴 422 | ⚠️ DIFF (HEUR) | 1000000 | ✅ PASS (Both Solved) | +| cremaschi2018-textbook-acce... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1000000 | ✅ PASS (MZN Reject, RS Solve) | +| cremaschi2018-textbook-acce... | MONO | False | 🟢 200 | 🟢 200 | 🔴 422 | ⚠️ RS NoSol | 1000000 | ✅ PASS (MZN Solved, RS NoSol) | +| cremaschi2018-textbook-acce... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1000000 | ✅ PASS (MZN Reject, RS Solve) | +| cremaschi2018-textbook-acce... | MULTI | False | 🔴 422 | 🔴 422 | 🔴 422 | - | - | ✅ PASS (All Rejected) | +| cremaschi2018-textbook-acce... | MULTI | True | 🔴 422 | 🔴 422 | 🔴 422 | - | - | ✅ PASS (All Rejected) | +| netedu2020-transport-agency... | MANY | False | 🔴 422 | 🔴 422 | 🟢 200 | - | - | ✅ PASS (MZN/RS Reject, MANY Solve) | +| netedu2020-transport-agency... | MANY | True | 🔴 422 | 🔴 422 | 🟢 200 | - | - | ✅ PASS (MZN/RS Reject, MANY Solve) | +| netedu2020-transport-agency... | MONO | False | 🟢 200 | 🟢 200 | 🔴 422 | ⚠️ DIFF (HEUR) | 1000000 | ✅ PASS (Both Solved) | +| netedu2020-transport-agency... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1000000 | ✅ PASS (MZN Reject, RS Solve) | +| netedu2020-transport-agency... | MONO | False | 🟢 200 | 🟢 200 | 🔴 422 | ⚠️ DIFF (HEUR) | 1000000 | ✅ PASS (Both Solved) | +| netedu2020-transport-agency... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1000000 | ✅ PASS (MZN Reject, RS Solve) | +| netedu2020-transport-agency... | MULTI | False | 🔴 422 | 🔴 422 | 🔴 422 | - | - | ✅ PASS (All Rejected) | +| netedu2020-transport-agency... | MULTI | True | 🔴 422 | 🔴 422 | 🔴 422 | - | - | ✅ PASS (All Rejected) | +| pautasso2009-restful-ecomme... | MANY | False | 🔴 422 | 🔴 422 | 🟢 200 | - | - | ❌ FAIL (MANY NoSol) | +| pautasso2009-restful-ecomme... | MANY | True | 🔴 422 | 🔴 422 | 🟢 200 | - | - | ✅ PASS (MZN/RS Reject, MANY Solve) | +| pautasso2009-restful-ecomme... | MONO | False | 🟢 200 | 🟢 200 | 🔴 422 | ✅ No Sol | 1594323 | ✅ PASS (MZN Solved, RS NoSol) | +| pautasso2009-restful-ecomme... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1594323 | ✅ PASS (MZN Reject, RS Solve) | +| pautasso2009-restful-ecomme... | MONO | False | 🟢 200 | 🟢 200 | 🔴 422 | ✅ No Sol | 1594323 | ✅ PASS (MZN Solved, RS NoSol) | +| pautasso2009-restful-ecomme... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1594323 | ✅ PASS (MZN Reject, RS Solve) | +| pautasso2009-restful-ecomme... | MULTI | False | 🔴 422 | 🔴 422 | 🔴 422 | - | - | ✅ PASS (All Rejected) | +| pautasso2009-restful-ecomme... | MULTI | True | 🔴 422 | 🔴 422 | 🔴 422 | - | - | ✅ PASS (All Rejected) | +| zhang2014-entertainment-pla... | MANY | True | 🔴 422 | 🔴 422 | 🟢 200 | - | - | ✅ PASS (MZN/RS Reject, MANY Solve) | +| zhang2014-entertainment-pla... | MANY | True | 🔴 422 | 🔴 422 | 🟢 200 | - | - | ✅ PASS (MZN/RS Reject, MANY Solve) | +| zhang2014-entertainment-pla... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1000000 | ✅ PASS (MZN Reject, RS Solve) | +| zhang2014-entertainment-pla... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1000000 | ✅ PASS (MZN Reject, RS Solve) | +| zhang2014-entertainment-pla... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1000000 | ✅ PASS (MZN Reject, RS Solve) | +| zhang2014-entertainment-pla... | MONO | True | 🔴 422 | 🟢 200 | 🔴 422 | - | 1000000 | ✅ PASS (MZN Reject, RS Solve) | +| zhang2014-entertainment-pla... | MULTI | True | 🔴 422 | 🔴 422 | 🔴 422 | - | - | ✅ PASS (All Rejected) | +| zhang2014-entertainment-pla... | MULTI | True | 🔴 422 | 🔴 422 | 🔴 422 | - | - | ✅ PASS (All Rejected) | + +## Detailed Results + +### benatallah2002-selfserv-travel-solution-cts-itas_many_hard.json ![Fail](https://img.shields.io/badge/Result-FAIL-critical) + +- **Objective**: `MANY` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.12s | See below | +| **Random Search** | 🔴 422 | 0.11s | See below | + +| **Many Heuristic** | 🟢 200 | 0.45s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "solutions": [], + "provenance": { + "engine_id": "many-heuristic", + "execution_time_ms": 0.0, + "metadata": { + "error": "No feasible solution found after 100000 iterations." + } + } +} +``` + +
+ +--- +### benatallah2002-selfserv-travel-solution-cts-itas_many_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MANY` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.11s | See below | +| **Random Search** | 🔴 422 | 0.12s | See below | + +| **Many Heuristic** | 🟢 200 | 25.98s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1301.98, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_accommodation_booking_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_accommodation_booking'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 927.58, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_accommodation_booking', 't_attractions_search'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_accommodation_booking', 't_car_rental_booking'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1301.98, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_accommodation_booking_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_accommodation_booking'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 927.58, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_accommodation_booking', 't_attractions_search'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_accommodation_booking', 't_car_rental_booking'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Binding Solution**: +```json +{ + "t_car_rental_booking": "t_car_rental_booking_gen_3", + "t_flight_booking_international": "t_flight_booking_international_gen_5", + "t_attractions_search": "t_attractions_search_gen_4", + "t_accommodation_booking": "t_accommodation_booking_gen_2", + "t_flight_booking_domestic": "t_flight_booking_domestic_gen_2", + "t_travel_insurance": "t_travel_insurance_gen_2" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1292.419, + "cost_usd": 1631.925, + "availability": 0.9729703676946407, + "gen_feat_1": 1348.8470000000002, + "gen_feat_2": 0.08071788735113516, + "gen_feat_3": 1341.9470000000001 +} +``` + +
+ +--- +### benatallah2002-selfserv-travel-solution-cts-itas_mono_one_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🟢 200 | 2.16s | See below | +| **Random Search** | 🟢 200 | 0.84s | See below | + +| **Many Heuristic** | 🔴 422 | 0.10s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Binding Solution**: +```json +{ + "t_attractions_search": "t_attractions_search_gen_2", + "t_flight_booking_domestic": "t_flight_booking_domestic_gen_3", + "t_flight_booking_international": "t_flight_booking_international_gen_1", + "t_travel_insurance": "svc_tis_2", + "t_accommodation_booking": "t_accommodation_booking_gen_8", + "t_car_rental_booking": "t_car_rental_booking_gen_2" +} +``` +**Aggregated Features**: +```json +{ + "availability": 0.29988, + "cost_usd": 1601.213, + "gen_feat_1": 1357.25, + "gen_feat_2": 0.01507608825824881, + "gen_feat_3": 1356.785, + "latency_ms": 1285.7569999999998 +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_car_rental_booking": "svc_crs_2", + "t_flight_booking_international": "svc_ifbs_2", + "t_attractions_search": "t_attractions_search_gen_2", + "t_accommodation_booking": "t_accommodation_booking_gen_8", + "t_flight_booking_domestic": "svc_dfbs_2", + "t_travel_insurance": "svc_tis_2" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1128.07, + "cost_usd": 1682.8200000000002, + "availability": 0.98761823424, + "gen_feat_1": 1347.81, + "gen_feat_2": 0.0866291739183, + "gen_feat_3": 1359.16 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### benatallah2002-selfserv-travel-solution-cts-itas_mono_one_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.10s | See below | +| **Random Search** | 🟢 200 | 0.78s | See below | + +| **Many Heuristic** | 🔴 422 | 0.11s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1301.98, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_accommodation_booking_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_accommodation_booking'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 927.58, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_accommodation_booking', 't_attractions_search'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_accommodation_booking', 't_car_rental_booking'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1301.98, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_accommodation_booking_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_accommodation_booking'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 927.58, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_accommodation_booking', 't_attractions_search'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_accommodation_booking', 't_car_rental_booking'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_car_rental_booking": "t_car_rental_booking_gen_2", + "t_flight_booking_international": "t_flight_booking_international_gen_3", + "t_attractions_search": "t_attractions_search_gen_6", + "t_accommodation_booking": "t_accommodation_booking_gen_6", + "t_flight_booking_domestic": "t_flight_booking_domestic_gen_3", + "t_travel_insurance": "t_travel_insurance_gen_5" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1339.023, + "cost_usd": 1618.713, + "availability": 1.0, + "gen_feat_1": 1363.038, + "gen_feat_2": 0.08515209015332184, + "gen_feat_3": 1337.4050000000002 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### benatallah2002-selfserv-travel-solution-cts-itas_mono_utility_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🟢 200 | 2.21s | See below | +| **Random Search** | 🟢 200 | 0.94s | See below | + +| **Many Heuristic** | 🔴 422 | 0.10s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Binding Solution**: +```json +{ + "t_attractions_search": "t_attractions_search_gen_2", + "t_flight_booking_domestic": "t_flight_booking_domestic_gen_3", + "t_flight_booking_international": "t_flight_booking_international_gen_7", + "t_travel_insurance": "svc_tis_2", + "t_accommodation_booking": "t_accommodation_booking_gen_8", + "t_car_rental_booking": "t_car_rental_booking_gen_8" +} +``` +**Aggregated Features**: +```json +{ + "availability": 0.29988, + "cost_usd": 1593.3509999999999, + "gen_feat_1": 1363.183, + "gen_feat_2": 0.015413767884388389, + "gen_feat_3": 1354.689, + "latency_ms": 1289.883 +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "solutions": [], + "provenance": { + "engine_id": "random-search", + "execution_time_ms": 0.0, + "metadata": { + "error": "No feasible solution found after 100000 iterations." + } + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### benatallah2002-selfserv-travel-solution-cts-itas_mono_utility_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.11s | See below | +| **Random Search** | 🟢 200 | 0.79s | See below | + +| **Many Heuristic** | 🔴 422 | 0.12s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1301.98, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_accommodation_booking_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_accommodation_booking'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 927.58, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_accommodation_booking', 't_attractions_search'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_accommodation_booking', 't_car_rental_booking'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1301.98, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_accommodation_booking_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_accommodation_booking'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 927.58, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_accommodation_booking', 't_attractions_search'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_accommodation_booking', 't_car_rental_booking'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_car_rental_booking": "t_car_rental_booking_gen_8", + "t_flight_booking_international": "t_flight_booking_international_gen_7", + "t_attractions_search": "t_attractions_search_gen_2", + "t_accommodation_booking": "t_accommodation_booking_gen_8", + "t_flight_booking_domestic": "t_flight_booking_domestic_gen_3", + "t_travel_insurance": "t_travel_insurance_gen_7" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1312.499, + "cost_usd": 1587.311, + "availability": 0.999776, + "gen_feat_1": 1360.3709999999999, + "gen_feat_2": 0.08701002110300539, + "gen_feat_3": 1353.529 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### benatallah2002-selfserv-travel-solution-cts-itas_multi_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MULTI` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | đź”´ 422 | 0.11s | See below | +| **Random Search** | đź”´ 422 | 0.18s | See below | + +| **Many Heuristic** | đź”´ 422 | 0.10s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### benatallah2002-selfserv-travel-solution-cts-itas_multi_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MULTI` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | đź”´ 422 | 0.10s | See below | +| **Random Search** | đź”´ 422 | 0.10s | See below | + +| **Many Heuristic** | đź”´ 422 | 0.10s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1301.98, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_accommodation_booking_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_accommodation_booking'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 927.58, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_accommodation_booking', 't_attractions_search'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_accommodation_booking', 't_car_rental_booking'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1301.98, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_accommodation_booking_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_accommodation_booking'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 927.58, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_accommodation_booking', 't_attractions_search'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_accommodation_booking', 't_car_rental_booking'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### bultan2003-warehouse-example_many_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MANY` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.31s | See below | +| **Random Search** | 🔴 422 | 0.28s | See below | + +| **Many Heuristic** | 🟢 200 | 5.54s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Binding Solution**: +```json +{ + "t_payment1": "t_payment1_gen_1", + "t_ok": "c_ok_bank_v1", + "t_payment2": "c_payment2_bank_v1", + "t_bill2": "t_bill2_gen_2", + "t_authorize": "t_authorize_gen_2", + "t_order2": "t_order2_gen_2", + "t_order1": "c_order1_store_v1", + "t_bill1": "t_bill1_gen_3", + "t_receipt1": "t_receipt1_gen_1", + "t_receipt2": "t_receipt2_gen_1" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1323.07, + "cost_usd": 0.8200000000000001, + "availability": 0.7854076157452324, + "gen_feat_1": 8483.310000000001, + "gen_feat_2": 2.74254397351582e-13, + "gen_feat_3": 8542.39 +} +``` + +
+ +--- +### bultan2003-warehouse-example_many_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MANY` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.29s | See below | +| **Random Search** | 🔴 422 | 0.26s | See below | + +| **Many Heuristic** | 🟢 200 | 32.95s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1318.72, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_authorize_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_authorize'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.01, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_authorize', 't_bill1'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_authorize', 't_payment2'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1318.72, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_authorize_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_authorize'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.01, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_authorize', 't_bill1'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_authorize', 't_payment2'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Binding Solution**: +```json +{ + "t_payment1": "t_payment1_gen_2", + "t_ok": "t_ok_gen_2", + "t_payment2": "t_payment2_gen_3", + "t_bill2": "t_bill2_gen_1", + "t_authorize": "c_authorize_store_v1", + "t_order2": "t_order2_gen_3", + "t_order1": "t_order1_gen_1", + "t_bill1": "t_bill1_gen_3", + "t_receipt1": "c_receipt1_wh1_v1", + "t_receipt2": "t_receipt2_gen_1" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1318.72, + "cost_usd": 0.7450000000000001, + "availability": 0.636445063004079, + "gen_feat_1": 8470.460000000001, + "gen_feat_2": 2.403736559720548e-13, + "gen_feat_3": 8499.91 +} +``` + +
+ +--- +### bultan2003-warehouse-example_mono_one_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🟢 200 | 24.54s | See below | +| **Random Search** | 🟢 200 | 1.52s | See below | + +| **Many Heuristic** | 🔴 422 | 0.29s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "solutions": [], + "provenance": { + "engine_id": "minizinc-csp", + "execution_time_ms": 0.0, + "metadata": {} + }, + "diagnostics": { + "warnings": [ + "Option 'iterations_count' is not supported by MiniZinc engine" + ], + "binding_space": { + "cardinality": "1048576", + "log10_cardinality": 6.020599913279624, + "per_task_counts": { + "t_authorize": 4, + "t_ok": 4, + "t_order1": 4, + "t_receipt1": 4, + "t_bill1": 4, + "t_payment1": 4, + "t_order2": 4, + "t_receipt2": 4, + "t_bill2": 4, + "t_payment2": 4 + }, + "empty_tasks": [] + } + } +} +``` +**MiniZinc No-Solution Analysis (based on RS binding)**: +```json +{ + "binding": { + "t_payment1": "t_payment1_gen_2", + "t_ok": "c_ok_bank_v1", + "t_payment2": "c_payment2_bank_v1", + "t_bill2": "t_bill2_gen_3", + "t_authorize": "t_authorize_gen_1", + "t_order2": "c_order2_store_v1", + "t_order1": "c_order1_store_v1", + "t_bill1": "t_bill1_gen_1", + "t_receipt1": "t_receipt1_gen_2", + "t_receipt2": "t_receipt2_gen_1" + }, + "aggregated_features": { + "latency_ms": 1322.8799999999999, + "cost_usd": 0.77, + "availability": 0.9686616388059096, + "gen_feat_1": 8573.23, + "gen_feat_2": 2.6119565004449756e-13, + "gen_feat_3": 8567.359999999999 + }, + "aggregated_features_scaled": { + "latency_ms": 0.26457600000000003, + "cost_usd": 0.00077, + "availability": 0.9686616388059096, + "gen_feat_1": 8.57323, + "gen_feat_2": 2.6119565004449756e-13, + "gen_feat_3": 8.56736 + }, + "aggregated_features_mzn_scaled": { + "latency_ms": 0.117954, + "cost_usd": 0.00031999999999999997, + "availability": 0.9833143761389193, + "gen_feat_1": 4.0329999999999995, + "gen_feat_2": 4.029334544069859e-06, + "gen_feat_3": 4.0354399999999995 + }, + "node_qos_mzn_scaled": { + "n_root_seq": { + "kind": "SEQ", + "latency_ms": 0.117954, + "cost_usd": 0.00031999999999999997, + "availability": 0.9833143761389193, + "gen_feat_1": 4.0329999999999995, + "gen_feat_2": 4.029334544069859e-06, + "gen_feat_3": 4.0354399999999995 + }, + "n_authorize": { + "kind": "TASK", + "latency_ms": 0.011206, + "cost_usd": 1e-05, + "availability": 0.9942, + "gen_feat_1": 0.50618, + "gen_feat_2": 0.499392, + "gen_feat_3": 0.51416 + }, + "n_ok": { + "kind": "TASK", + "latency_ms": 0.009, + "cost_usd": 1e-05, + "availability": 0.999, + "gen_feat_1": 0.5, + "gen_feat_2": 0.5, + "gen_feat_3": 0.5 + }, + "n_parallel_orders": { + "kind": "AND", + "latency_ms": 0.097748, + "cost_usd": 0.0003, + "availability": 0.9900409121039359, + "gen_feat_1": 3.02682, + "gen_feat_2": 1.6136960720515582e-05, + "gen_feat_3": 3.02128 + }, + "n_loop_wh1": { + "kind": "LOOP", + "latency_ms": 0.091972, + "cost_usd": 0.00014, + "availability": 0.996004, + "gen_feat_1": 2.98076, + "gen_feat_2": 0.004024886875005128, + "gen_feat_3": 3.02128 + }, + "n_wh1_iter_seq": { + "kind": "SEQ", + "latency_ms": 0.045986, + "cost_usd": 7e-05, + "availability": 0.998, + "gen_feat_1": 1.49038, + "gen_feat_2": 0.06344199614612649, + "gen_feat_3": 1.51064 + }, + "n_order1": { + "kind": "TASK", + "latency_ms": 0.013, + "cost_usd": 2e-05, + "availability": 0.998, + "gen_feat_1": 0.5, + "gen_feat_2": 0.5, + "gen_feat_3": 0.5 + }, + "n_wh1_after_order": { + "kind": "AND", + "latency_ms": 0.032986, + "cost_usd": 4.9999999999999996e-05, + "availability": 1.0, + "gen_feat_1": 0.99038, + "gen_feat_2": 0.12688399229225297, + "gen_feat_3": 1.01064 + }, + "n_receipt1": { + "kind": "TASK", + "latency_ms": 0.015556, + "cost_usd": 1e-05, + "availability": 1.0, + "gen_feat_1": 0.5120800000000001, + "gen_feat_2": 0.510897, + "gen_feat_3": 0.48677 + }, + "n_wh1_billpay": { + "kind": "SEQ", + "latency_ms": 0.032986, + "cost_usd": 3.9999999999999996e-05, + "availability": 1.0, + "gen_feat_1": 0.99038, + "gen_feat_2": 0.24835532855400003, + "gen_feat_3": 1.01064 + }, + "n_bill1": { + "kind": "TASK", + "latency_ms": 0.014846000000000002, + "cost_usd": 1e-05, + "availability": 1.0, + "gen_feat_1": 0.49945999999999996, + "gen_feat_2": 0.510726, + "gen_feat_3": 0.50743 + }, + "n_payment1": { + "kind": "TASK", + "latency_ms": 0.01814, + "cost_usd": 2.9999999999999997e-05, + "availability": 1.0, + "gen_feat_1": 0.49092, + "gen_feat_2": 0.486279, + "gen_feat_3": 0.5032099999999999 + }, + "n_loop_wh2": { + "kind": "LOOP", + "latency_ms": 0.097748, + "cost_usd": 0.00015999999999999999, + "availability": 0.9940129880039998, + "gen_feat_1": 3.02682, + "gen_feat_2": 0.004009295471315581, + "gen_feat_3": 3.02028 + }, + "n_wh2_iter_seq": { + "kind": "SEQ", + "latency_ms": 0.048874, + "cost_usd": 7.999999999999999e-05, + "availability": 0.9970019999999999, + "gen_feat_1": 1.51341, + "gen_feat_2": 0.0633189977125, + "gen_feat_3": 1.51014 + }, + "n_order2": { + "kind": "TASK", + "latency_ms": 0.014, + "cost_usd": 2e-05, + "availability": 0.998, + "gen_feat_1": 0.5, + "gen_feat_2": 0.5, + "gen_feat_3": 0.5 + }, + "n_wh2_after_order": { + "kind": "AND", + "latency_ms": 0.034874, + "cost_usd": 5.9999999999999995e-05, + "availability": 0.999, + "gen_feat_1": 1.01341, + "gen_feat_2": 0.126637995425, + "gen_feat_3": 1.01014 + }, + "n_receipt2": { + "kind": "TASK", + "latency_ms": 0.016584, + "cost_usd": 1e-05, + "availability": 1.0, + "gen_feat_1": 0.49435, + "gen_feat_2": 0.50285, + "gen_feat_3": 0.50712 + }, + "n_wh2_billpay": { + "kind": "SEQ", + "latency_ms": 0.034874, + "cost_usd": 4.9999999999999996e-05, + "availability": 0.999, + "gen_feat_1": 1.01341, + "gen_feat_2": 0.2518405, + "gen_feat_3": 1.01014 + }, + "n_bill2": { + "kind": "TASK", + "latency_ms": 0.015874, + "cost_usd": 2e-05, + "availability": 1.0, + "gen_feat_1": 0.5134099999999999, + "gen_feat_2": 0.503681, + "gen_feat_3": 0.51014 + }, + "n_payment2": { + "kind": "TASK", + "latency_ms": 0.019, + "cost_usd": 2.9999999999999997e-05, + "availability": 0.999, + "gen_feat_1": 0.5, + "gen_feat_2": 0.5, + "gen_feat_3": 0.5 + } + }, + "qos_ub": { + "latency_ms": 1.5004199999999999, + "cost_usd": 1.0, + "availability": 1.0, + "gen_feat_1": 50.837900000000005, + "gen_feat_2": 1.0, + "gen_feat_3": 50.860299999999995 + }, + "bound_violations": [ + { + "constraint_id": "gen_c_global_latency_ms_1", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "current": 1322.8799999999999, + "op": "<=", + "value": 1318.72 + } + ], + "mzn_scaled_bound_violations": [ + { + "constraint_id": "gen_c_global_latency_ms_1", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "current_scaled": 0.26457600000000003, + "op": "<=", + "value_scaled": 0.263744 + } + ], + "mzn_loop_scaled_bound_violations": [], + "qos_ub_violations": [], + "qos_ub_node_violations": [], + "dependency_violations": [], + "notes": [] +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_payment1": "t_payment1_gen_2", + "t_ok": "c_ok_bank_v1", + "t_payment2": "c_payment2_bank_v1", + "t_bill2": "t_bill2_gen_3", + "t_authorize": "t_authorize_gen_1", + "t_order2": "c_order2_store_v1", + "t_order1": "c_order1_store_v1", + "t_bill1": "t_bill1_gen_1", + "t_receipt1": "t_receipt1_gen_2", + "t_receipt2": "t_receipt2_gen_1" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1322.8799999999999, + "cost_usd": 0.77, + "availability": 0.9686616388059096, + "gen_feat_1": 8573.23, + "gen_feat_2": 2.6119565004449756e-13, + "gen_feat_3": 8567.359999999999 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### bultan2003-warehouse-example_mono_one_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.28s | See below | +| **Random Search** | 🟢 200 | 1.30s | See below | + +| **Many Heuristic** | 🔴 422 | 0.25s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1318.72, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_authorize_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_authorize'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.01, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_authorize', 't_bill1'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_authorize', 't_payment2'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1318.72, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_authorize_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_authorize'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.01, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_authorize', 't_bill1'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_authorize', 't_payment2'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_payment1": "t_payment1_gen_2", + "t_ok": "t_ok_gen_2", + "t_payment2": "c_payment2_bank_v1", + "t_bill2": "t_bill2_gen_3", + "t_authorize": "t_authorize_gen_3", + "t_order2": "c_order2_store_v1", + "t_order1": "c_order1_store_v1", + "t_bill1": "t_bill1_gen_3", + "t_receipt1": "t_receipt1_gen_2", + "t_receipt2": "t_receipt2_gen_1" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1324.6999999999998, + "cost_usd": 0.77, + "availability": 0.9752879401287323, + "gen_feat_1": 8568.939999999999, + "gen_feat_2": 2.72244988682062e-13, + "gen_feat_3": 8564.019999999999 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### bultan2003-warehouse-example_mono_utility_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🟢 200 | 168.14s | See below | +| **Random Search** | 🟢 200 | 1.45s | See below | + +| **Many Heuristic** | 🔴 422 | 0.28s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "solutions": [], + "provenance": { + "engine_id": "minizinc-csp", + "execution_time_ms": 0.0, + "metadata": {} + }, + "diagnostics": { + "warnings": [ + "Option 'iterations_count' is not supported by MiniZinc engine" + ], + "binding_space": { + "cardinality": "1048576", + "log10_cardinality": 6.020599913279624, + "per_task_counts": { + "t_authorize": 4, + "t_ok": 4, + "t_order1": 4, + "t_receipt1": 4, + "t_bill1": 4, + "t_payment1": 4, + "t_order2": 4, + "t_receipt2": 4, + "t_bill2": 4, + "t_payment2": 4 + }, + "empty_tasks": [] + } + } +} +``` +**MiniZinc No-Solution Analysis (based on RS binding)**: +```json +{ + "binding": { + "t_payment1": "t_payment1_gen_1", + "t_ok": "t_ok_gen_2", + "t_payment2": "c_payment2_bank_v1", + "t_bill2": "t_bill2_gen_3", + "t_authorize": "t_authorize_gen_1", + "t_order2": "c_order2_store_v1", + "t_order1": "c_order1_store_v1", + "t_bill1": "t_bill1_gen_1", + "t_receipt1": "t_receipt1_gen_3", + "t_receipt2": "t_receipt2_gen_1" + }, + "aggregated_features": { + "latency_ms": 1324.1999999999998, + "cost_usd": 0.8200000000000001, + "availability": 0.9696312700759856, + "gen_feat_1": 8562.99, + "gen_feat_2": 2.3732296002486986e-13, + "gen_feat_3": 8563.97 + }, + "aggregated_features_scaled": { + "latency_ms": 0.26484, + "cost_usd": 0.00082, + "availability": 0.9696312700759856, + "gen_feat_1": 8.56299, + "gen_feat_2": 2.3732296002486986e-13, + "gen_feat_3": 8.56397 + }, + "aggregated_features_mzn_scaled": { + "latency_ms": 0.118218, + "cost_usd": 0.00033999999999999997, + "availability": 0.984298674813733, + "gen_feat_1": 4.02276, + "gen_feat_2": 3.837127743106285e-06, + "gen_feat_3": 4.03355 + }, + "node_qos_mzn_scaled": { + "n_root_seq": { + "kind": "SEQ", + "latency_ms": 0.118218, + "cost_usd": 0.00033999999999999997, + "availability": 0.984298674813733, + "gen_feat_1": 4.02276, + "gen_feat_2": 3.837127743106285e-06, + "gen_feat_3": 4.03355 + }, + "n_authorize": { + "kind": "TASK", + "latency_ms": 0.011206, + "cost_usd": 1e-05, + "availability": 0.9942, + "gen_feat_1": 0.50618, + "gen_feat_2": 0.499392, + "gen_feat_3": 0.51416 + }, + "n_ok": { + "kind": "TASK", + "latency_ms": 0.009264, + "cost_usd": 1e-05, + "availability": 1.0, + "gen_feat_1": 0.48976, + "gen_feat_2": 0.491295, + "gen_feat_3": 0.49911 + }, + "n_parallel_orders": { + "kind": "AND", + "latency_ms": 0.097748, + "cost_usd": 0.00031999999999999997, + "availability": 0.9900409121039359, + "gen_feat_1": 3.02682, + "gen_feat_2": 1.5639480846096922e-05, + "gen_feat_3": 3.02028 + }, + "n_loop_wh1": { + "kind": "LOOP", + "latency_ms": 0.092724, + "cost_usd": 0.00015999999999999999, + "availability": 0.996004, + "gen_feat_1": 2.96936, + "gen_feat_2": 0.003900805255683762, + "gen_feat_3": 3.01508 + }, + "n_wh1_iter_seq": { + "kind": "SEQ", + "latency_ms": 0.046362, + "cost_usd": 7.999999999999999e-05, + "availability": 0.998, + "gen_feat_1": 1.48468, + "gen_feat_2": 0.062456426856519434, + "gen_feat_3": 1.50754 + }, + "n_order1": { + "kind": "TASK", + "latency_ms": 0.013, + "cost_usd": 2e-05, + "availability": 0.998, + "gen_feat_1": 0.5, + "gen_feat_2": 0.5, + "gen_feat_3": 0.5 + }, + "n_wh1_after_order": { + "kind": "AND", + "latency_ms": 0.033362, + "cost_usd": 5.9999999999999995e-05, + "availability": 1.0, + "gen_feat_1": 0.98468, + "gen_feat_2": 0.12491285371303887, + "gen_feat_3": 1.00754 + }, + "n_receipt1": { + "kind": "TASK", + "latency_ms": 0.016022, + "cost_usd": 2e-05, + "availability": 1.0, + "gen_feat_1": 0.50814, + "gen_feat_2": 0.486315, + "gen_feat_3": 0.48994 + }, + "n_wh1_billpay": { + "kind": "SEQ", + "latency_ms": 0.033362, + "cost_usd": 3.9999999999999996e-05, + "availability": 1.0, + "gen_feat_1": 0.98468, + "gen_feat_2": 0.256855852098, + "gen_feat_3": 1.00754 + }, + "n_bill1": { + "kind": "TASK", + "latency_ms": 0.014846000000000002, + "cost_usd": 1e-05, + "availability": 1.0, + "gen_feat_1": 0.49945999999999996, + "gen_feat_2": 0.510726, + "gen_feat_3": 0.50743 + }, + "n_payment1": { + "kind": "TASK", + "latency_ms": 0.018516, + "cost_usd": 2.9999999999999997e-05, + "availability": 1.0, + "gen_feat_1": 0.48522000000000004, + "gen_feat_2": 0.502923, + "gen_feat_3": 0.50011 + }, + "n_loop_wh2": { + "kind": "LOOP", + "latency_ms": 0.097748, + "cost_usd": 0.00015999999999999999, + "availability": 0.9940129880039998, + "gen_feat_1": 3.02682, + "gen_feat_2": 0.004009295471315581, + "gen_feat_3": 3.02028 + }, + "n_wh2_iter_seq": { + "kind": "SEQ", + "latency_ms": 0.048874, + "cost_usd": 7.999999999999999e-05, + "availability": 0.9970019999999999, + "gen_feat_1": 1.51341, + "gen_feat_2": 0.0633189977125, + "gen_feat_3": 1.51014 + }, + "n_order2": { + "kind": "TASK", + "latency_ms": 0.014, + "cost_usd": 2e-05, + "availability": 0.998, + "gen_feat_1": 0.5, + "gen_feat_2": 0.5, + "gen_feat_3": 0.5 + }, + "n_wh2_after_order": { + "kind": "AND", + "latency_ms": 0.034874, + "cost_usd": 5.9999999999999995e-05, + "availability": 0.999, + "gen_feat_1": 1.01341, + "gen_feat_2": 0.126637995425, + "gen_feat_3": 1.01014 + }, + "n_receipt2": { + "kind": "TASK", + "latency_ms": 0.016584, + "cost_usd": 1e-05, + "availability": 1.0, + "gen_feat_1": 0.49435, + "gen_feat_2": 0.50285, + "gen_feat_3": 0.50712 + }, + "n_wh2_billpay": { + "kind": "SEQ", + "latency_ms": 0.034874, + "cost_usd": 4.9999999999999996e-05, + "availability": 0.999, + "gen_feat_1": 1.01341, + "gen_feat_2": 0.2518405, + "gen_feat_3": 1.01014 + }, + "n_bill2": { + "kind": "TASK", + "latency_ms": 0.015874, + "cost_usd": 2e-05, + "availability": 1.0, + "gen_feat_1": 0.5134099999999999, + "gen_feat_2": 0.503681, + "gen_feat_3": 0.51014 + }, + "n_payment2": { + "kind": "TASK", + "latency_ms": 0.019, + "cost_usd": 2.9999999999999997e-05, + "availability": 0.999, + "gen_feat_1": 0.5, + "gen_feat_2": 0.5, + "gen_feat_3": 0.5 + } + }, + "qos_ub": { + "latency_ms": 1.5004199999999999, + "cost_usd": 1.0, + "availability": 1.0, + "gen_feat_1": 50.837900000000005, + "gen_feat_2": 1.0, + "gen_feat_3": 50.860299999999995 + }, + "bound_violations": [ + { + "constraint_id": "gen_c_global_latency_ms_1", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "current": 1324.1999999999998, + "op": "<=", + "value": 1318.72 + } + ], + "mzn_scaled_bound_violations": [ + { + "constraint_id": "gen_c_global_latency_ms_1", + "scope": "GLOBAL", + "attribute_id": "latency_ms", + "current_scaled": 0.26484, + "op": "<=", + "value_scaled": 0.263744 + } + ], + "mzn_loop_scaled_bound_violations": [], + "qos_ub_violations": [], + "qos_ub_node_violations": [], + "dependency_violations": [], + "notes": [] +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_payment1": "t_payment1_gen_1", + "t_ok": "t_ok_gen_2", + "t_payment2": "c_payment2_bank_v1", + "t_bill2": "t_bill2_gen_3", + "t_authorize": "t_authorize_gen_1", + "t_order2": "c_order2_store_v1", + "t_order1": "c_order1_store_v1", + "t_bill1": "t_bill1_gen_1", + "t_receipt1": "t_receipt1_gen_3", + "t_receipt2": "t_receipt2_gen_1" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1324.1999999999998, + "cost_usd": 0.8200000000000001, + "availability": 0.9696312700759856, + "gen_feat_1": 8562.99, + "gen_feat_2": 2.3732296002486986e-13, + "gen_feat_3": 8563.97 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### bultan2003-warehouse-example_mono_utility_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.25s | See below | +| **Random Search** | 🟢 200 | 1.27s | See below | + +| **Many Heuristic** | 🔴 422 | 0.23s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1318.72, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_authorize_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_authorize'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.01, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_authorize', 't_bill1'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_authorize', 't_payment2'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1318.72, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_authorize_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_authorize'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.01, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_authorize', 't_bill1'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_authorize', 't_payment2'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_payment1": "t_payment1_gen_1", + "t_ok": "t_ok_gen_3", + "t_payment2": "c_payment2_bank_v1", + "t_bill2": "t_bill2_gen_3", + "t_authorize": "t_authorize_gen_3", + "t_order2": "c_order2_store_v1", + "t_order1": "c_order1_store_v1", + "t_bill1": "t_bill1_gen_1", + "t_receipt1": "t_receipt1_gen_3", + "t_receipt2": "t_receipt2_gen_1" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1322.56, + "cost_usd": 0.8200000000000001, + "availability": 0.9752879401287323, + "gen_feat_1": 8591.96, + "gen_feat_2": 2.5007884399532516e-13, + "gen_feat_3": 8577.419999999998 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### bultan2003-warehouse-example_multi_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MULTI` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | đź”´ 422 | 0.26s | See below | +| **Random Search** | đź”´ 422 | 0.24s | See below | + +| **Many Heuristic** | đź”´ 422 | 0.28s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### bultan2003-warehouse-example_multi_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MULTI` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | đź”´ 422 | 0.26s | See below | +| **Random Search** | đź”´ 422 | 0.27s | See below | + +| **Many Heuristic** | đź”´ 422 | 0.25s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1318.72, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_authorize_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_authorize'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.01, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_authorize', 't_bill1'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_authorize', 't_payment2'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1318.72, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_authorize_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_authorize'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.01, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_authorize', 't_bill1'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_authorize', 't_payment2'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### cremaschi2018-textbook-access_many_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MANY` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.07s | See below | +| **Random Search** | 🔴 422 | 0.07s | See below | + +| **Many Heuristic** | 🟢 200 | 0.98s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Binding Solution**: +```json +{ + "t_geocoding": "t_geocoding_gen_3", + "t_market": "t_market_gen_2", + "t_books": "t_books_gen_7", + "t_library": "t_library_gen_6", + "t_archive": "t_archive_gen_6", + "t_transit": "t_transit_gen_6" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1336.0, + "cost_usd": 0.0, + "availability": 0.9103450359483279, + "gen_feat_1": 1990.6499999999999, + "gen_feat_2": 0.016177752000527006, + "gen_feat_3": 2026.61 +} +``` + +
+ +--- +### cremaschi2018-textbook-access_many_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MANY` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.07s | See below | +| **Random Search** | 🔴 422 | 0.07s | See below | + +| **Many Heuristic** | 🟢 200 | 14.26s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1357.94, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_archive_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_archive'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_books', 't_geocoding'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_archive', 't_books'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1357.94, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_archive_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_archive'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_books', 't_geocoding'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_archive', 't_books'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Binding Solution**: +```json +{ + "t_geocoding": "t_geocoding_gen_6", + "t_market": "t_market_gen_8", + "t_books": "t_books_gen_1", + "t_library": "t_library_gen_2", + "t_archive": "t_archive_gen_5", + "t_transit": "t_transit_gen_6" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1332.98, + "cost_usd": 0.0, + "availability": 0.9099815467393042, + "gen_feat_1": 2010.15, + "gen_feat_2": 0.01668334975676384, + "gen_feat_3": 2003.82 +} +``` + +
+ +--- +### cremaschi2018-textbook-access_mono_one_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🟢 200 | 2.15s | See below | +| **Random Search** | 🟢 200 | 0.67s | See below | + +| **Many Heuristic** | 🔴 422 | 0.08s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Binding Solution**: +```json +{ + "t_books": "c_google_books_api", + "t_market": "t_market_gen_1", + "t_library": "t_library_gen_1", + "t_geocoding": "c_google_geocoding_api", + "t_transit": "t_transit_gen_8", + "t_archive": "t_archive_gen_5" +} +``` +**Aggregated Features**: +```json +{ + "availability": 0.0, + "cost_usd": 0.0021, + "gen_feat_1": 1990.24, + "gen_feat_2": 0.0, + "gen_feat_3": 2025.06, + "latency_ms": 1337.42 +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_geocoding": "c_google_geocoding_api", + "t_market": "t_market_gen_1", + "t_books": "c_google_books_api", + "t_library": "t_library_gen_8", + "t_archive": "t_archive_gen_5", + "t_transit": "t_transit_gen_8" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1344.35, + "cost_usd": 0.0021, + "availability": 0.9871024462000001, + "gen_feat_1": 1971.94, + "gen_feat_2": 0.014823842982264065, + "gen_feat_3": 2010.23 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### cremaschi2018-textbook-access_mono_one_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.08s | See below | +| **Random Search** | 🟢 200 | 0.64s | See below | + +| **Many Heuristic** | 🔴 422 | 0.11s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1357.94, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_archive_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_archive'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_books', 't_geocoding'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_archive', 't_books'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1357.94, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_archive_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_archive'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_books', 't_geocoding'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_archive', 't_books'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_geocoding": "t_geocoding_gen_7", + "t_market": "t_market_gen_9", + "t_books": "t_books_gen_5", + "t_library": "t_library_gen_8", + "t_archive": "t_archive_gen_5", + "t_transit": "t_transit_gen_8" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1338.19, + "cost_usd": 0.0, + "availability": 0.997048, + "gen_feat_1": 1956.6599999999999, + "gen_feat_2": 0.014732872713510647, + "gen_feat_3": 2006.8899999999999 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### cremaschi2018-textbook-access_mono_utility_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🟢 200 | 2.13s | See below | +| **Random Search** | 🟢 200 | 0.64s | See below | + +| **Many Heuristic** | 🔴 422 | 0.07s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Binding Solution**: +```json +{ + "t_books": "c_google_books_api", + "t_market": "t_market_gen_9", + "t_library": "t_library_gen_8", + "t_geocoding": "c_google_geocoding_api", + "t_transit": "t_transit_gen_8", + "t_archive": "t_archive_gen_5" +} +``` +**Aggregated Features**: +```json +{ + "availability": 0.0, + "cost_usd": 0.0021, + "gen_feat_1": 1971.94, + "gen_feat_2": 0.0, + "gen_feat_3": 2010.23, + "latency_ms": 1344.35 +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "solutions": [], + "provenance": { + "engine_id": "random-search", + "execution_time_ms": 0.0, + "metadata": { + "error": "No feasible solution found after 100000 iterations." + } + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### cremaschi2018-textbook-access_mono_utility_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.08s | See below | +| **Random Search** | 🟢 200 | 0.51s | See below | + +| **Many Heuristic** | 🔴 422 | 0.07s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1357.94, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_archive_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_archive'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_books', 't_geocoding'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_archive', 't_books'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1357.94, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_archive_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_archive'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_books', 't_geocoding'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_archive', 't_books'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_geocoding": "t_geocoding_gen_7", + "t_market": "t_market_gen_9", + "t_books": "t_books_gen_5", + "t_library": "t_library_gen_8", + "t_archive": "t_archive_gen_5", + "t_transit": "t_transit_gen_8" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 1338.19, + "cost_usd": 0.0, + "availability": 0.997048, + "gen_feat_1": 1956.6599999999999, + "gen_feat_2": 0.014732872713510647, + "gen_feat_3": 2006.8899999999999 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### cremaschi2018-textbook-access_multi_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MULTI` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | đź”´ 422 | 0.07s | See below | +| **Random Search** | đź”´ 422 | 0.07s | See below | + +| **Many Heuristic** | đź”´ 422 | 0.07s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### cremaschi2018-textbook-access_multi_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MULTI` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | đź”´ 422 | 0.08s | See below | +| **Random Search** | đź”´ 422 | 0.08s | See below | + +| **Many Heuristic** | đź”´ 422 | 0.08s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1357.94, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_archive_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_archive'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_books', 't_geocoding'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_archive', 't_books'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1357.94, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_archive_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_archive'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_books', 't_geocoding'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_archive', 't_books'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### netedu2020-transport-agency_many_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MANY` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.05s | See below | +| **Random Search** | 🔴 422 | 0.07s | See below | + +| **Many Heuristic** | 🟢 200 | 0.49s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Binding Solution**: +```json +{ + "t_get_country_from_location": "t_get_country_from_location_gen_2", + "t_get_closest_city": "t_get_closest_city_gen_4", + "t_make_arrangements": "t_make_arrangements_gen_8", + "t_get_local_subsidiary": "t_get_local_subsidiary_gen_4", + "t_get_vehicle": "c_get_vehicle", + "t_get_transport_company": "t_get_transport_company_gen_6" +} +``` +**Aggregated Features**: +```json +{ + "cost": 5.99, + "gen_feat_1": 2984.35, + "gen_feat_2": 0.01670215031980321, + "gen_feat_3": 3007.71 +} +``` + +
+ +--- +### netedu2020-transport-agency_many_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MANY` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.06s | See below | +| **Random Search** | 🔴 422 | 0.06s | See below | + +| **Many Heuristic** | 🟢 200 | 4.00s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 6.01, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_get_closest_city_gen_feat_1_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_get_closest_city'], 'attribute_id': 'gen_feat_1', 'op': '<=', 'value': 497.52, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_get_closest_city', 't_get_country_from_location'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_get_closest_city', 't_make_arrangements'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 6.01, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_get_closest_city_gen_feat_1_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_get_closest_city'], 'attribute_id': 'gen_feat_1', 'op': '<=', 'value': 497.52, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_get_closest_city', 't_get_country_from_location'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_get_closest_city', 't_make_arrangements'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Binding Solution**: +```json +{ + "t_get_country_from_location": "t_get_country_from_location_gen_1", + "t_get_closest_city": "t_get_closest_city_gen_1", + "t_make_arrangements": "t_make_arrangements_gen_7", + "t_get_local_subsidiary": "t_get_local_subsidiary_gen_4", + "t_get_vehicle": "c_get_vehicle", + "t_get_transport_company": "t_get_transport_company_gen_7" +} +``` +**Aggregated Features**: +```json +{ + "cost": 6.029999999999999, + "gen_feat_1": 3004.34, + "gen_feat_2": 0.017272189035961963, + "gen_feat_3": 2985.21 +} +``` + +
+ +--- +### netedu2020-transport-agency_mono_one_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🟢 200 | 2.11s | See below | +| **Random Search** | 🟢 200 | 0.33s | See below | + +| **Many Heuristic** | 🔴 422 | 0.04s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Binding Solution**: +```json +{ + "t_get_country_from_location": "t_get_country_from_location_gen_2", + "t_get_transport_company": "t_get_transport_company_gen_2", + "t_get_closest_city": "t_get_closest_city_gen_4", + "t_get_local_subsidiary": "t_get_local_subsidiary_gen_7", + "t_get_vehicle": "t_get_vehicle_gen_2", + "t_make_arrangements": "t_make_arrangements_gen_3" +} +``` +**Aggregated Features**: +```json +{ + "cost": 5.9, + "gen_feat_1": 2979.77, + "gen_feat_2": 0.01635108076074883, + "gen_feat_3": 2981.58 +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_get_country_from_location": "t_get_country_from_location_gen_2", + "t_get_closest_city": "t_get_closest_city_gen_4", + "t_make_arrangements": "t_make_arrangements_gen_3", + "t_get_local_subsidiary": "t_get_local_subsidiary_gen_7", + "t_get_vehicle": "t_get_vehicle_gen_3", + "t_get_transport_company": "t_get_transport_company_gen_3" +} +``` +**Aggregated Features**: +```json +{ + "cost": 5.9, + "gen_feat_1": 2982.92, + "gen_feat_2": 0.016539281124164595, + "gen_feat_3": 3002.41 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### netedu2020-transport-agency_mono_one_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.05s | See below | +| **Random Search** | 🟢 200 | 0.28s | See below | + +| **Many Heuristic** | 🔴 422 | 0.05s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 6.01, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_get_closest_city_gen_feat_1_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_get_closest_city'], 'attribute_id': 'gen_feat_1', 'op': '<=', 'value': 497.52, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_get_closest_city', 't_get_country_from_location'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_get_closest_city', 't_make_arrangements'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 6.01, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_get_closest_city_gen_feat_1_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_get_closest_city'], 'attribute_id': 'gen_feat_1', 'op': '<=', 'value': 497.52, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_get_closest_city', 't_get_country_from_location'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_get_closest_city', 't_make_arrangements'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_get_country_from_location": "t_get_country_from_location_gen_2", + "t_get_closest_city": "t_get_closest_city_gen_3", + "t_make_arrangements": "t_make_arrangements_gen_3", + "t_get_local_subsidiary": "t_get_local_subsidiary_gen_7", + "t_get_vehicle": "t_get_vehicle_gen_6", + "t_get_transport_company": "t_get_transport_company_gen_3" +} +``` +**Aggregated Features**: +```json +{ + "cost": 5.880000000000001, + "gen_feat_1": 3024.57, + "gen_feat_2": 0.016939678748017963, + "gen_feat_3": 3017.37 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### netedu2020-transport-agency_mono_utility_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🟢 200 | 2.10s | See below | +| **Random Search** | 🟢 200 | 0.34s | See below | + +| **Many Heuristic** | 🔴 422 | 0.06s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Binding Solution**: +```json +{ + "t_get_country_from_location": "t_get_country_from_location_gen_2", + "t_get_transport_company": "t_get_transport_company_gen_2", + "t_get_closest_city": "t_get_closest_city_gen_4", + "t_get_local_subsidiary": "t_get_local_subsidiary_gen_4", + "t_get_vehicle": "t_get_vehicle_gen_2", + "t_make_arrangements": "t_make_arrangements_gen_7" +} +``` +**Aggregated Features**: +```json +{ + "cost": 5.99, + "gen_feat_1": 2967.9399999999996, + "gen_feat_2": 0.01700032920258602, + "gen_feat_3": 2979.2000000000003 +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_get_country_from_location": "t_get_country_from_location_gen_2", + "t_get_closest_city": "t_get_closest_city_gen_4", + "t_make_arrangements": "t_make_arrangements_gen_7", + "t_get_local_subsidiary": "t_get_local_subsidiary_gen_4", + "t_get_vehicle": "t_get_vehicle_gen_2", + "t_get_transport_company": "c_get_transport_company" +} +``` +**Aggregated Features**: +```json +{ + "cost": 6.01, + "gen_feat_1": 2962.16, + "gen_feat_2": 0.017050594354743806, + "gen_feat_3": 2991.7000000000003 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### netedu2020-transport-agency_mono_utility_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.06s | See below | +| **Random Search** | 🟢 200 | 0.29s | See below | + +| **Many Heuristic** | 🔴 422 | 0.05s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 6.01, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_get_closest_city_gen_feat_1_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_get_closest_city'], 'attribute_id': 'gen_feat_1', 'op': '<=', 'value': 497.52, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_get_closest_city', 't_get_country_from_location'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_get_closest_city', 't_make_arrangements'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 6.01, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_get_closest_city_gen_feat_1_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_get_closest_city'], 'attribute_id': 'gen_feat_1', 'op': '<=', 'value': 497.52, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_get_closest_city', 't_get_country_from_location'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_get_closest_city', 't_make_arrangements'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_get_country_from_location": "t_get_country_from_location_gen_1", + "t_get_closest_city": "t_get_closest_city_gen_4", + "t_make_arrangements": "t_make_arrangements_gen_7", + "t_get_local_subsidiary": "t_get_local_subsidiary_gen_4", + "t_get_vehicle": "t_get_vehicle_gen_2", + "t_get_transport_company": "t_get_transport_company_gen_5" +} +``` +**Aggregated Features**: +```json +{ + "cost": 6.02, + "gen_feat_1": 2981.29, + "gen_feat_2": 0.01678403681377613, + "gen_feat_3": 2955.27 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### netedu2020-transport-agency_multi_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MULTI` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | đź”´ 422 | 0.05s | See below | +| **Random Search** | đź”´ 422 | 0.05s | See below | + +| **Many Heuristic** | đź”´ 422 | 0.05s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### netedu2020-transport-agency_multi_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MULTI` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | đź”´ 422 | 0.05s | See below | +| **Random Search** | đź”´ 422 | 0.05s | See below | + +| **Many Heuristic** | đź”´ 422 | 0.05s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 6.01, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_get_closest_city_gen_feat_1_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_get_closest_city'], 'attribute_id': 'gen_feat_1', 'op': '<=', 'value': 497.52, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_get_closest_city', 't_get_country_from_location'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_get_closest_city', 't_make_arrangements'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 6.01, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_get_closest_city_gen_feat_1_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_get_closest_city'], 'attribute_id': 'gen_feat_1', 'op': '<=', 'value': 497.52, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_get_closest_city', 't_get_country_from_location'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_get_closest_city', 't_make_arrangements'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### pautasso2009-restful-ecommerce_many_hard.json ![Fail](https://img.shields.io/badge/Result-FAIL-critical) + +- **Objective**: `MANY` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.13s | See below | +| **Random Search** | 🔴 422 | 0.20s | See below | + +| **Many Heuristic** | 🟢 200 | 0.61s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "solutions": [], + "provenance": { + "engine_id": "many-heuristic", + "execution_time_ms": 0.0, + "metadata": { + "error": "No feasible solution found after 100000 iterations." + } + }, + "diagnostics": { + "warnings": [ + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[0].hard'", + "details": { + "path": "constraints[0].hard", + "value": true + } + }, + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[1].hard'", + "details": { + "path": "constraints[1].hard", + "value": true + } + }, + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[2].hard'", + "details": { + "path": "constraints[2].hard", + "value": true + } + } + ] + } +} +``` + +
+ +--- +### pautasso2009-restful-ecommerce_many_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MANY` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.12s | See below | +| **Random Search** | 🔴 422 | 0.12s | See below | + +| **Many Heuristic** | 🟢 200 | 51.57s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'bind_shop_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_create_order', 't_add_item', 't_remove_item', 't_get_amount', 't_checkout', 't_list_confirmed', 't_ship_order', 't_update_shipment', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'bind_catalog_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_request_quote', 't_get_quote'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'bind_payment_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_charge_payment', 't_refund_payment'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 2060.44, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_add_item_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_add_item'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.4\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_add_item', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.5\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_add_item', 't_charge_payment'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.6\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'bind_shop_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_create_order', 't_add_item', 't_remove_item', 't_get_amount', 't_checkout', 't_list_confirmed', 't_ship_order', 't_update_shipment', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'bind_catalog_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_request_quote', 't_get_quote'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'bind_payment_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_charge_payment', 't_refund_payment'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 2060.44, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_add_item_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_add_item'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.4", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_add_item', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.5", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_add_item', 't_charge_payment'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.6", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Binding Solution**: +```json +{ + "t_add_item": "c_shopB_add_item", + "t_remove_item": "c_shopB_remove_item", + "t_update_shipment": "c_shopA_update_shipment", + "t_charge_payment": "t_charge_payment_gen_1", + "t_create_order": "t_create_order_gen_1", + "t_get_amount": "c_shopB_get_amount", + "t_cancel_order": "t_cancel_order_gen_1", + "t_request_quote": "c_catalogA_request_quote", + "t_checkout": "c_shopA_checkout", + "t_get_quote": "c_catalogB_get_quote", + "t_refund_payment": "c_paymentA_refund", + "t_list_confirmed": "c_shopA_list_confirmed", + "t_ship_order": "t_ship_order_gen_1" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 2077.08275, + "cost_usd": 0.07035975, + "availability": 0.9502990614557736, + "gen_feat_1": 6388.60635, + "gen_feat_2": 0.0005387195502929085, + "gen_feat_3": 6385.5465 +} +``` + +
+ +--- +### pautasso2009-restful-ecommerce_mono_one_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🟢 200 | 2.20s | See below | +| **Random Search** | 🟢 200 | 1.58s | See below | + +| **Many Heuristic** | 🔴 422 | 0.12s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "solutions": [], + "provenance": { + "engine_id": "minizinc-csp", + "execution_time_ms": 203.0, + "metadata": { + "solver": "gecode", + "time_sec": 0.203 + } + }, + "diagnostics": { + "warnings": [ + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[0].hard'", + "details": { + "path": "constraints[0].hard", + "value": true + } + }, + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[1].hard'", + "details": { + "path": "constraints[1].hard", + "value": true + } + }, + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[2].hard'", + "details": { + "path": "constraints[2].hard", + "value": true + } + }, + "Option 'iterations_count' is not supported by MiniZinc engine" + ], + "binding_space": { + "cardinality": "1594323", + "log10_cardinality": 6.202576311355613, + "per_task_counts": { + "t_create_order": 3, + "t_request_quote": 3, + "t_get_quote": 3, + "t_add_item": 3, + "t_remove_item": 3, + "t_get_amount": 3, + "t_checkout": 3, + "t_charge_payment": 3, + "t_list_confirmed": 3, + "t_ship_order": 3, + "t_update_shipment": 3, + "t_cancel_order": 3, + "t_refund_payment": 3 + }, + "empty_tasks": [] + } + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "solutions": [], + "provenance": { + "engine_id": "random-search", + "execution_time_ms": 0.0, + "metadata": { + "error": "No feasible solution found after 100000 iterations." + } + }, + "diagnostics": { + "warnings": [ + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[0].hard'", + "details": { + "path": "constraints[0].hard", + "value": true + } + }, + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[1].hard'", + "details": { + "path": "constraints[1].hard", + "value": true + } + }, + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[2].hard'", + "details": { + "path": "constraints[2].hard", + "value": true + } + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### pautasso2009-restful-ecommerce_mono_one_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.12s | See below | +| **Random Search** | 🟢 200 | 1.24s | See below | + +| **Many Heuristic** | 🔴 422 | 0.13s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'bind_shop_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_create_order', 't_add_item', 't_remove_item', 't_get_amount', 't_checkout', 't_list_confirmed', 't_ship_order', 't_update_shipment', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'bind_catalog_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_request_quote', 't_get_quote'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'bind_payment_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_charge_payment', 't_refund_payment'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1866.14, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_add_item_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_add_item'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.4\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_add_item', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.5\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_add_item', 't_refund_payment'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.6\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'bind_shop_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_create_order', 't_add_item', 't_remove_item', 't_get_amount', 't_checkout', 't_list_confirmed', 't_ship_order', 't_update_shipment', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'bind_catalog_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_request_quote', 't_get_quote'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'bind_payment_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_charge_payment', 't_refund_payment'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1866.14, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_add_item_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_add_item'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.4", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_add_item', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.5", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_add_item', 't_refund_payment'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.6", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_add_item": "c_shopB_add_item", + "t_remove_item": "c_shopB_remove_item", + "t_update_shipment": "t_update_shipment_gen_1", + "t_charge_payment": "c_paymentB_charge", + "t_create_order": "c_shopB_create_order", + "t_get_amount": "c_shopA_get_amount", + "t_cancel_order": "c_shopB_cancel_order", + "t_request_quote": "c_catalogB_request_quote", + "t_checkout": "c_shopB_checkout", + "t_get_quote": "c_catalogB_get_quote", + "t_refund_payment": "c_paymentB_refund", + "t_list_confirmed": "c_shopA_list_confirmed", + "t_ship_order": "c_shopB_ship_order" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 2416.13235, + "cost_usd": 0.06203, + "availability": 0.9858829983915486, + "gen_feat_1": 6379.902550000001, + "gen_feat_2": 0.000535443476956177, + "gen_feat_3": 6384.24595 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### pautasso2009-restful-ecommerce_mono_utility_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🟢 200 | 2.23s | See below | +| **Random Search** | 🟢 200 | 1.48s | See below | + +| **Many Heuristic** | 🔴 422 | 0.10s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "solutions": [], + "provenance": { + "engine_id": "minizinc-csp", + "execution_time_ms": 0.0, + "metadata": {} + }, + "diagnostics": { + "warnings": [ + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[0].hard'", + "details": { + "path": "constraints[0].hard", + "value": true + } + }, + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[1].hard'", + "details": { + "path": "constraints[1].hard", + "value": true + } + }, + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[2].hard'", + "details": { + "path": "constraints[2].hard", + "value": true + } + }, + "Option 'iterations_count' is not supported by MiniZinc engine" + ], + "binding_space": { + "cardinality": "1594323", + "log10_cardinality": 6.202576311355613, + "per_task_counts": { + "t_create_order": 3, + "t_request_quote": 3, + "t_get_quote": 3, + "t_add_item": 3, + "t_remove_item": 3, + "t_get_amount": 3, + "t_checkout": 3, + "t_charge_payment": 3, + "t_list_confirmed": 3, + "t_ship_order": 3, + "t_update_shipment": 3, + "t_cancel_order": 3, + "t_refund_payment": 3 + }, + "empty_tasks": [] + } + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "solutions": [], + "provenance": { + "engine_id": "random-search", + "execution_time_ms": 0.0, + "metadata": { + "error": "No feasible solution found after 100000 iterations." + } + }, + "diagnostics": { + "warnings": [ + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[0].hard'", + "details": { + "path": "constraints[0].hard", + "value": true + } + }, + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[1].hard'", + "details": { + "path": "constraints[1].hard", + "value": true + } + }, + { + "code": "DEFAULT_APPLIED", + "message": "Applied default for 'constraints[2].hard'", + "details": { + "path": "constraints[2].hard", + "value": true + } + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### pautasso2009-restful-ecommerce_mono_utility_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.12s | See below | +| **Random Search** | 🟢 200 | 1.35s | See below | + +| **Many Heuristic** | 🔴 422 | 0.13s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'bind_shop_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_create_order', 't_add_item', 't_remove_item', 't_get_amount', 't_checkout', 't_list_confirmed', 't_ship_order', 't_update_shipment', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'bind_catalog_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_request_quote', 't_get_quote'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'bind_payment_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_charge_payment', 't_refund_payment'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 2259.82, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_add_item_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_add_item'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.4\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_add_item', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.5\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_add_item', 't_charge_payment'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.6\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'bind_shop_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_create_order', 't_add_item', 't_remove_item', 't_get_amount', 't_checkout', 't_list_confirmed', 't_ship_order', 't_update_shipment', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'bind_catalog_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_request_quote', 't_get_quote'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'bind_payment_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_charge_payment', 't_refund_payment'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 2259.82, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_add_item_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_add_item'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.4", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_add_item', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.5", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_add_item', 't_charge_payment'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.6", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_add_item": "c_shopB_add_item", + "t_remove_item": "c_shopB_remove_item", + "t_update_shipment": "t_update_shipment_gen_1", + "t_charge_payment": "c_paymentB_charge", + "t_create_order": "c_shopB_create_order", + "t_get_amount": "c_shopB_get_amount", + "t_cancel_order": "c_shopB_cancel_order", + "t_request_quote": "c_catalogB_request_quote", + "t_checkout": "c_shopB_checkout", + "t_get_quote": "t_get_quote_gen_1", + "t_refund_payment": "c_paymentA_refund", + "t_list_confirmed": "c_shopB_list_confirmed", + "t_ship_order": "c_shopB_ship_order" +} +``` +**Aggregated Features**: +```json +{ + "latency_ms": 2295.14235, + "cost_usd": 0.060565249999999994, + "availability": 0.9874786465055755, + "gen_feat_1": 6379.083550000001, + "gen_feat_2": 0.0005341248336548596, + "gen_feat_3": 6368.70595 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### pautasso2009-restful-ecommerce_multi_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MULTI` +- **Soft Constraints**: `False` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | đź”´ 422 | 0.12s | See below | +| **Random Search** | đź”´ 422 | 0.14s | See below | + +| **Many Heuristic** | đź”´ 422 | 0.17s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### pautasso2009-restful-ecommerce_multi_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MULTI` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | đź”´ 422 | 0.12s | See below | +| **Random Search** | đź”´ 422 | 0.13s | See below | + +| **Many Heuristic** | đź”´ 422 | 0.13s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'bind_shop_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_create_order', 't_add_item', 't_remove_item', 't_get_amount', 't_checkout', 't_list_confirmed', 't_ship_order', 't_update_shipment', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'bind_catalog_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_request_quote', 't_get_quote'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'bind_payment_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_charge_payment', 't_refund_payment'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1866.14, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_add_item_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_add_item'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.4\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_add_item', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.5\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_add_item', 't_refund_payment'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.6\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'bind_shop_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_create_order', 't_add_item', 't_remove_item', 't_get_amount', 't_checkout', 't_list_confirmed', 't_ship_order', 't_update_shipment', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'bind_catalog_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_request_quote', 't_get_quote'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'bind_payment_mono_provider', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_charge_payment', 't_refund_payment'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_latency_ms_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'latency_ms', 'op': '<=', 'value': 1866.14, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_add_item_cost_usd_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_add_item'], 'attribute_id': 'cost_usd', 'op': '<=', 'value': 0.0, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.4", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_add_item', 't_cancel_order'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.5", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_add_item', 't_refund_payment'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.6", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### zhang2014-entertainment-planner-running-example_many_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MANY` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.31s | See below | +| **Random Search** | 🔴 422 | 0.23s | See below | + +| **Many Heuristic** | 🟢 200 | 0.73s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Binding Solution**: +```json +{ + "t_movie": "t_movie_gen_49", + "t_shopping": "t_shopping_gen_54", + "t_dining": "t_dining_gen_34" +} +``` +**Aggregated Features**: +```json +{ + "cost": 49.34, + "time": 238.23, + "distance": 1742.48, + "gen_feat_1": 1484.24, + "gen_feat_2": 0.127654928693071, + "gen_feat_3": 1470.56 +} +``` + +
+ +--- +### zhang2014-entertainment-planner-running-example_many_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MANY` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.21s | See below | +| **Random Search** | 🔴 422 | 0.20s | See below | + +| **Many Heuristic** | 🟢 200 | 4.78s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_within_2km', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'distance', 'op': '<=', 'value': 2000, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 50.07, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_dining_time_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_dining'], 'attribute_id': 'time', 'op': '<=', 'value': 59.79, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.4\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_dining', 't_shopping'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.5\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_dining', 't_movie'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.6\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_within_2km', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'distance', 'op': '<=', 'value': 2000, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 50.07, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_dining_time_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_dining'], 'attribute_id': 'time', 'op': '<=', 'value': 59.79, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.4", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_dining', 't_shopping'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.5", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_dining', 't_movie'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.6", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Binding Solution**: +```json +{ + "t_movie": "t_movie_gen_75", + "t_shopping": "t_shopping_gen_8", + "t_dining": "t_dining_gen_70" +} +``` +**Aggregated Features**: +```json +{ + "cost": 49.37, + "time": 238.52999999999997, + "distance": 1745.08, + "gen_feat_1": 1485.29, + "gen_feat_2": 0.12341086186106176, + "gen_feat_3": 1512.32 +} +``` + +
+ +--- +### zhang2014-entertainment-planner-running-example_mono_one_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.18s | See below | +| **Random Search** | 🟢 200 | 0.60s | See below | + +| **Many Heuristic** | 🔴 422 | 0.18s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_movie": "t_movie_gen_92", + "t_shopping": "t_shopping_gen_47", + "t_dining": "t_dining_gen_90" +} +``` +**Aggregated Features**: +```json +{ + "cost": 48.709999999999994, + "time": 241.07, + "distance": 1744.3, + "gen_feat_1": 1491.76, + "gen_feat_2": 0.12513207296593443, + "gen_feat_3": 1502.74 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### zhang2014-entertainment-planner-running-example_mono_one_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.19s | See below | +| **Random Search** | 🟢 200 | 0.55s | See below | + +| **Many Heuristic** | 🔴 422 | 0.20s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'c_within_2km', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'distance', 'op': '<=', 'value': 2000, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 50.07, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_dining_time_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_dining'], 'attribute_id': 'time', 'op': '<=', 'value': 59.79, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.4\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_dining', 't_shopping'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.5\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_dining', 't_movie'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.6\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_within_2km', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'distance', 'op': '<=', 'value': 2000, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 50.07, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_dining_time_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_dining'], 'attribute_id': 'time', 'op': '<=', 'value': 59.79, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.4", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_dining', 't_shopping'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.5", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_dining', 't_movie'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.6", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_movie": "t_movie_gen_52", + "t_shopping": "t_shopping_gen_47", + "t_dining": "t_dining_gen_23" +} +``` +**Aggregated Features**: +```json +{ + "cost": 48.56, + "time": 239.94, + "distance": 1679.04, + "gen_feat_1": 1481.8, + "gen_feat_2": 0.1218078120493523, + "gen_feat_3": 1473.95 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### zhang2014-entertainment-planner-running-example_mono_utility_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.21s | See below | +| **Random Search** | 🟢 200 | 0.66s | See below | + +| **Many Heuristic** | 🔴 422 | 0.22s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_movie": "t_movie_gen_34", + "t_shopping": "t_shopping_gen_37", + "t_dining": "t_dining_gen_44" +} +``` +**Aggregated Features**: +```json +{ + "cost": 49.980000000000004, + "time": 235.16, + "distance": 1663.09, + "gen_feat_1": 1494.8, + "gen_feat_2": 0.13385978664750445, + "gen_feat_3": 1494.98 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### zhang2014-entertainment-planner-running-example_mono_utility_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MONO` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | 🔴 422 | 0.32s | See below | +| **Random Search** | 🟢 200 | 0.59s | See below | + +| **Many Heuristic** | 🔴 422 | 0.20s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"{'id': 'c_within_2km', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'distance', 'op': '<=', 'value': 2000, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 50.07, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_dining_time_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_dining'], 'attribute_id': 'time', 'op': '<=', 'value': 59.79, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.4\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_dining', 't_shopping'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.5\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_dining', 't_movie'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.6\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_within_2km', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'distance', 'op': '<=', 'value': 2000, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 50.07, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_dining_time_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_dining'], 'attribute_id': 'time', 'op': '<=', 'value': 59.79, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.4", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_dining', 't_shopping'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.5", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_dining', 't_movie'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.6", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Binding Solution**: +```json +{ + "t_movie": "t_movie_gen_88", + "t_shopping": "t_shopping_gen_8", + "t_dining": "t_dining_gen_44" +} +``` +**Aggregated Features**: +```json +{ + "cost": 50.160000000000004, + "time": 233.43, + "distance": 1660.59, + "gen_feat_1": 1472.47, + "gen_feat_2": 0.1343835796979068, + "gen_feat_3": 1496.0100000000002 +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### zhang2014-entertainment-planner-running-example_multi_hard.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MULTI` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | đź”´ 422 | 0.18s | See below | +| **Random Search** | đź”´ 422 | 0.23s | See below | + +| **Many Heuristic** | đź”´ 422 | 0.18s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- +### zhang2014-entertainment-planner-running-example_multi_soft.json ![Pass](https://img.shields.io/badge/Result-PASS-success) + +- **Objective**: `MULTI` +- **Soft Constraints**: `True` + +| Engine | Status | Time | Result | +|---|---|---|---| +| **MiniZinc CSP** | đź”´ 422 | 0.19s | See below | +| **Random Search** | đź”´ 422 | 0.19s | See below | + +| **Many Heuristic** | đź”´ 422 | 0.20s | See below | + +
View Engine Responses + +#### MiniZinc CSP +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_within_2km', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'distance', 'op': '<=', 'value': 2000, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.0\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.1\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.2\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 50.07, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.3\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_local_t_dining_time_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_dining'], 'attribute_id': 'time', 'op': '<=', 'value': 59.79, 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.4\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_dining', 't_shopping'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.5\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}, {\"constraint_id\": null, \"message\": \"{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_dining', 't_movie'], 'hard': False} is not valid under any of the given schemas\", \"path\": \"constraints.6\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_within_2km', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'distance', 'op': '<=', 'value': 2000, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.0", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_time_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'time', 'op': '<=', 'value': 240, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.1", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'c_cost_budget', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 100, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.2", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_global_cost_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'GLOBAL', 'attribute_id': 'cost', 'op': '<=', 'value': 50.07, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.3", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_local_t_dining_time_1', 'kind': 'ATTRIBUTE_BOUND', 'scope': 'LOCAL', 'tasks': ['t_dining'], 'attribute_id': 'time', 'op': '<=', 'value': 59.79, 'hard': False} is not valid under any of the given schemas", + "path": "constraints.4", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_same_1', 'kind': 'DEPENDENCY', 'type': 'SAME_PROVIDER', 'tasks': ['t_dining', 't_shopping'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.5", + "constraint_id": null + }, + { + "code": "specialization_schema_invalid", + "message": "{'id': 'gen_c_dep_diff_1', 'kind': 'DEPENDENCY', 'type': 'DIFFERENT_PROVIDER', 'tasks': ['t_dining', 't_movie'], 'hard': False} is not valid under any of the given schemas", + "path": "constraints.6", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Random Search +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MONO' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MONO' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +--- +#### Many Heuristic +**Response**: +```json +{ + "detail": { + "error": "The problem has semantic or logical errors: [{\"constraint_id\": null, \"message\": \"'MANY' was expected\", \"path\": \"objective.type\", \"code\": \"specialization_schema_invalid\", \"stage\": \"specialization_schema\", \"penalty\": null, \"description\": null}]", + "violations": [ + { + "code": "specialization_schema_invalid", + "message": "'MANY' was expected", + "path": "objective.type", + "constraint_id": null + } + ] + } +} +``` + +
+ +--- diff --git a/experimentation/run_experiments.py b/experimentation/run_experiments.py new file mode 100644 index 0000000..837f875 --- /dev/null +++ b/experimentation/run_experiments.py @@ -0,0 +1,996 @@ +import os +import json +import requests +import time +from typing import Dict, Any, Tuple, Optional, List +from tqdm import tqdm +from termcolor import colored + +GATEWAY_URL = "http://localhost:8000/v1/solve" +INSTANCES_DIR = "experimentation/instances" +REPORT_FILE = "experimentation/report.md" +DEFAULT_ITERATIONS_COUNT = 100000 +MANY_ITERATIONS_COUNT = 100000 + +def build_selected_candidate_by_task( + selection: Dict[str, str], + candidates_by_id: Dict[str, Dict[str, Any]], +) -> Dict[str, Dict[str, Any]]: + selected: Dict[str, Dict[str, Any]] = {} + for task_id, cand_id in selection.items(): + cand = candidates_by_id.get(cand_id) + if cand is not None: + selected[task_id] = cand + return selected + + +def _default_for(feature_id: str, features: Dict[str, Any], agg_policies: Dict[str, Any]) -> float: + policy = agg_policies.get(feature_id, {}) + if "neutral" in policy and isinstance(policy.get("neutral"), (int, float)): + return float(policy["neutral"]) + feat = features.get(feature_id, {}) + direction = feat.get("direction") + vr = feat.get("valid_range") or {} + if direction == "maximize" or direction == "MAXIMIZE": + return float(vr.get("min", 0.0)) + return float(vr.get("max", 0.0)) + + +def _agg_fn(fn: Optional[str], values: List[float], weights: Optional[List[float]] = None) -> float: + if not values: + return 0.0 + + fn_lower = fn.lower() if fn else "" + + if fn_lower in ("weighted_sum",): + w = weights or [1.0] * len(values) + return sum(v * w_i for v, w_i in zip(values, w)) + if fn_lower == "sum": + if weights is not None: + return sum(v * w_i for v, w_i in zip(values, weights)) + return sum(values) + if fn_lower == "product": + res = 1.0 + for v in values: + res *= v + return res + if fn_lower == "max": + return max(values) + if fn_lower == "min": + return min(values) + return sum(values) + + +def _compose_value( + node: Dict[str, Any], + feature_id: str, + selected_candidate_by_task: Dict[str, Dict[str, Any]], + features: Dict[str, Any], + agg_policies: Dict[str, Any], +) -> float: + kind = node.get("kind") + policy = agg_policies.get(feature_id, {}) + compose = policy.get("compose", {}) + + if kind == "TASK": + task_id = node.get("task_id") + cand = selected_candidate_by_task.get(task_id) + if cand is None: + return _default_for(feature_id, features, agg_policies) + return float((cand.get("features", {}) or {}).get(feature_id, _default_for(feature_id, features, agg_policies))) + + if kind in ("SEQ", "AND"): + children = node.get("children", []) or [] + values = [_compose_value(c, feature_id, selected_candidate_by_task, features, agg_policies) for c in children] + fn = compose.get("seq" if kind == "SEQ" else "and", {}).get("fn") + return _agg_fn(fn or ("sum" if kind == "SEQ" else "max"), values) + + if kind == "XOR": + branches = node.get("branches", []) or [] + values = [_compose_value(b.get("child", {}), feature_id, selected_candidate_by_task, features, agg_policies) for b in branches] + probs = [float(b.get("p", 0.0)) for b in branches] + fn = compose.get("xor", {}).get("fn") + if fn in (None, "sum", "weighted_sum", "scaled_sum", "SCALED_SUM"): + return _agg_fn("weighted_sum", values, probs) + return _agg_fn(fn, values) + + if kind == "LOOP": + body = node.get("body", {}) or {} + body_val = _compose_value(body, feature_id, selected_candidate_by_task, features, agg_policies) + fn = compose.get("loop", {}).get("fn") + iterations = node.get("expected_iterations") + if iterations is None: + bounds = node.get("bounds") or {} + iterations = bounds.get("max", 1) + c = float(iterations) + + fn_lower = (fn or "sum").lower() + if "product" in fn_lower: + return float(body_val ** c) + if "sum" in fn_lower or "wsum" in fn_lower or "scale" in fn_lower: + return float(body_val * c) + return body_val + + return _default_for(feature_id, features, agg_policies) + + +def _compose_value_mzn( + node: Dict[str, Any], + feature_id: str, + selected_candidate_by_task: Dict[str, Dict[str, Any]], + features: Dict[str, Any], + agg_policies: Dict[str, Any], +) -> float: + kind = node.get("kind") + policy = agg_policies.get(feature_id, {}) + compose = policy.get("compose", {}) + + if kind == "TASK": + task_id = node.get("task_id") + cand = selected_candidate_by_task.get(task_id) + if cand is None: + return _default_for(feature_id, features, agg_policies) + return float((cand.get("features", {}) or {}).get(feature_id, _default_for(feature_id, features, agg_policies))) + + if kind in ("SEQ", "AND"): + children = node.get("children", []) or [] + values = [_compose_value_mzn(c, feature_id, selected_candidate_by_task, features, agg_policies) for c in children] + fn = compose.get("seq" if kind == "SEQ" else "and", {}).get("fn") + return _agg_fn(fn or ("sum" if kind == "SEQ" else "max"), values) + + if kind == "XOR": + branches = node.get("branches", []) or [] + values = [ + _compose_value_mzn(b.get("child", {}), feature_id, selected_candidate_by_task, features, agg_policies) + for b in branches + ] + probs = [float(b.get("p", 0.0)) for b in branches] + fn = compose.get("xor", {}).get("fn") + if fn in (None, "sum", "weighted_sum", "scaled_sum", "SCALED_SUM"): + return _agg_fn("weighted_sum", values, probs) + return _agg_fn(fn, values) + + if kind == "LOOP": + body = node.get("body", {}) or {} + body_val = _compose_value_mzn(body, feature_id, selected_candidate_by_task, features, agg_policies) + fn = compose.get("loop", {}).get("fn") + iterations = node.get("expected_iterations") + if iterations is None: + bounds = node.get("bounds") or {} + mn = float(bounds.get("min", 0)) + mx = float(bounds.get("max", 0)) + if mx > 0 or mn > 0: + iterations = (mn + mx) / 2.0 + if iterations is None: + iterations = node.get("iterations") + c = float(round(iterations or 1)) + + fn_lower = (fn or "sum").lower() + if "product" in fn_lower: + return float(body_val ** c) + if "sum" in fn_lower or "wsum" in fn_lower or "scale" in fn_lower: + return float(body_val * c) + return body_val + + return _default_for(feature_id, features, agg_policies) + + +def compute_aggregated_qos( + composition_root: Dict[str, Any], + features: Dict[str, Any], + selected_candidate_by_task: Dict[str, Dict[str, Any]], + agg_policies: Dict[str, Any], +) -> Dict[str, float]: + aggregated_qos: Dict[str, float] = {} + for fid in features.keys(): + aggregated_qos[fid] = _compose_value( + composition_root, + fid, + selected_candidate_by_task, + features, + agg_policies, + ) + return aggregated_qos + + +def compute_aggregated_qos_mzn( + composition_root: Dict[str, Any], + features: Dict[str, Any], + selected_candidate_by_task: Dict[str, Dict[str, Any]], + agg_policies: Dict[str, Any], +) -> Dict[str, float]: + aggregated_qos: Dict[str, float] = {} + for fid in features.keys(): + aggregated_qos[fid] = _compose_value_mzn( + composition_root, + fid, + selected_candidate_by_task, + features, + agg_policies, + ) + return aggregated_qos + + +def compute_node_qos_mzn( + node: Dict[str, Any], + features: Dict[str, Any], + selected_candidate_by_task: Dict[str, Dict[str, Any]], + agg_policies: Dict[str, Any], +) -> Dict[str, Dict[str, float]]: + results: Dict[str, Dict[str, float]] = {} + + def _node_id(n: Dict[str, Any]) -> str: + return n.get("id") or f"anon_{id(n)}" + + def _walk(n: Dict[str, Any]) -> None: + nid = _node_id(n) + values: Dict[str, float] = {} + for fid in features.keys(): + values[fid] = _compose_value_mzn(n, fid, selected_candidate_by_task, features, agg_policies) + results[nid] = {"kind": n.get("kind"), **values} + + if n.get("kind") in ("SEQ", "AND"): + for child in n.get("children", []) or []: + _walk(child) + elif n.get("kind") == "XOR": + for br in n.get("branches", []) or []: + _walk(br.get("child", {}) or {}) + elif n.get("kind") == "LOOP": + body = n.get("body", {}) or {} + _walk(body) + + _walk(node) + return results + + +def compute_qos_ub_mzn( + instance: Dict[str, Any], + features: Dict[str, Any], + scaled_selected_by_task: Dict[str, Dict[str, Any]], +) -> Dict[str, float]: + fn_map = { + "sum": 1, + "weighted_sum": 5, + "product": 2, + "max": 3, + "min": 4, + "scale_by_c": 1, + "scaled_sum": 1, + "scaled_product": 2, + } + + def _map_fn(fn: Optional[str], default_val: int) -> int: + if not fn: + return default_val + return fn_map.get(fn.lower(), default_val) + + tasks = instance.get("tasks", []) or [] + candidates = instance.get("candidates", []) or [] + task_ids = [t.get("id") for t in tasks if t.get("id")] + + task_candidates_map: Dict[str, List[int]] = {tid: [] for tid in task_ids} + cand_qos: List[Dict[str, float]] = [] + + for idx, cand in enumerate(candidates): + tid = cand.get("task_id") + if tid in task_candidates_map: + task_candidates_map[tid].append(idx) + scaled_features = {} + for fid, feat in features.items(): + raw_val = (cand.get("features", {}) or {}).get(fid) + if isinstance(raw_val, (int, float)): + scaled_features[fid] = _scale_value(float(raw_val), feat) + cand_qos.append(scaled_features) + + agg_policies = instance.get("aggregation_policies", {}) or {} + qos_ub: Dict[str, float] = {} + + for fid in features.keys(): + pol = agg_policies.get(fid, {}) or {} + compose = pol.get("compose", {}) or {} + + seq_pol = _map_fn(compose.get("seq", {}).get("fn"), 1) + loop_pol = _map_fn(compose.get("loop", {}).get("fn"), 1) + + is_availability = "availability" in fid.lower() or "success" in fid.lower() + max_val = 1.0 + if cand_qos: + max_val = max(1.0, max(abs(c.get(fid, 0.0)) for c in cand_qos)) + + if is_availability or seq_pol == 2 or loop_pol == 2: + qos_ub[fid] = 1.0 + elif seq_pol == 1 or loop_pol == 1: + task_sum = 0.0 + for tid in task_ids: + cidxs = task_candidates_map.get(tid, []) + if cidxs: + task_sum += max(abs(cand_qos[i].get(fid, 0.0)) for i in cidxs) + loop_factor = 10 + qos_ub[fid] = max(1.0, task_sum * loop_factor) + else: + qos_ub[fid] = max_val * 1.5 + + return qos_ub + + +def _scale_value(val: float, feat: Dict[str, Any]) -> float: + vr = feat.get("valid_range") or {} + mn = float(vr.get("min", 0.0)) + mx = float(vr.get("max", 1.0)) + denom = mx - mn + if abs(denom) < 1e-12: + return 0.0 + scaled = (float(val) - mn) / denom + if scaled < 0.0: + return 0.0 + if scaled > 1.0: + return 1.0 + return scaled + + +def _check_op(current: float, op: str, rhs: float) -> bool: + if op == "<=": + return current <= rhs + if op == "<": + return current < rhs + if op == ">=": + return current >= rhs + if op == ">": + return current > rhs + if op == "==": + return abs(current - rhs) <= 1e-9 + if op == "!=" or op == "<>": + return abs(current - rhs) > 1e-9 + return True + + +def analyze_mzn_no_solution(instance: Dict[str, Any], rs_resp: Dict[str, Any]) -> Optional[Dict[str, Any]]: + binding = get_binding(rs_resp) + if not binding: + return None + + candidates_by_id = {c["id"]: c for c in (instance.get("candidates", []) or [])} + features = {f["id"]: f for f in (instance.get("features", []) or [])} + agg_policies = instance.get("aggregation_policies", {}) or {} + selected_by_task = build_selected_candidate_by_task(binding, candidates_by_id) + root = (instance.get("composition", {}) or {}).get("root", {}) + aggregated = compute_aggregated_qos(root, features, selected_by_task, agg_policies) + + # Build a scaled view of selected candidates (MiniZinc-style scaling) + scaled_selected_by_task = {} + for task_id, cand in selected_by_task.items(): + scaled_features = {} + for fid, feat in features.items(): + raw_val = (cand.get("features", {}) or {}).get(fid) + if isinstance(raw_val, (int, float)): + scaled_features[fid] = _scale_value(float(raw_val), feat) + scaled_selected_by_task[task_id] = { + "id": cand.get("id"), + "provider_id": cand.get("provider_id"), + "features": scaled_features, + } + + aggregated_scaled = compute_aggregated_qos(root, features, scaled_selected_by_task, agg_policies) + aggregated_mzn_scaled = compute_aggregated_qos_mzn(root, features, scaled_selected_by_task, agg_policies) + qos_ub = compute_qos_ub_mzn(instance, features, scaled_selected_by_task) + node_qos_mzn_scaled = compute_node_qos_mzn(root, features, scaled_selected_by_task, agg_policies) + + bound_violations = [] + scaled_bound_violations = [] + mzn_scaled_bound_violations = [] + qos_ub_violations = [] + qos_ub_node_violations = [] + dependency_violations = [] + notes = [] + + for c in (instance.get("constraints", []) or []): + if c.get("hard") is False: + continue + kind = (c.get("kind") or "").upper() + if kind == "ATTRIBUTE_BOUND": + scope = (c.get("scope") or "").upper() + attr = c.get("attribute_id") + op = c.get("op") + if not attr or not op: + continue + value = c.get("value") + if isinstance(value, dict) and op in ("IN_RANGE", "in_range"): + min_val = value.get("min") + max_val = value.get("max") + if scope == "GLOBAL": + current = aggregated.get(attr) + else: + task_id = c.get("task_id") or (c.get("tasks") or [None])[0] + cand = selected_by_task.get(task_id) + current = None if cand is None else (cand.get("features", {}) or {}).get(attr) + if current is None: + notes.append({"constraint_id": c.get("id"), "reason": "missing_value"}) + else: + if (min_val is not None and current < min_val) or (max_val is not None and current > max_val): + bound_violations.append({ + "constraint_id": c.get("id"), + "scope": scope, + "attribute_id": attr, + "current": current, + "min": min_val, + "max": max_val, + }) + continue + if not isinstance(value, (int, float)): + continue + if scope == "GLOBAL": + current = aggregated.get(attr) + current_scaled = aggregated_scaled.get(attr) + if current is None: + notes.append({"constraint_id": c.get("id"), "reason": "missing_aggregated_feature"}) + continue + else: + task_id = c.get("task_id") or (c.get("tasks") or [None])[0] + cand = selected_by_task.get(task_id) + if cand is None: + notes.append({"constraint_id": c.get("id"), "reason": "missing_task_binding"}) + continue + current = (cand.get("features", {}) or {}).get(attr) + if current is None: + notes.append({"constraint_id": c.get("id"), "reason": "missing_candidate_feature"}) + continue + cand_scaled = scaled_selected_by_task.get(task_id) + current_scaled = None + if cand_scaled is not None: + current_scaled = (cand_scaled.get("features", {}) or {}).get(attr) + if not _check_op(float(current), op, float(value)): + bound_violations.append({ + "constraint_id": c.get("id"), + "scope": scope, + "attribute_id": attr, + "current": current, + "op": op, + "value": value, + }) + + feat = features.get(attr) + if feat is not None and isinstance(value, (int, float)) and current_scaled is not None: + scaled_value = _scale_value(float(value), feat) + if not _check_op(float(current_scaled), op, float(scaled_value)): + scaled_bound_violations.append({ + "constraint_id": c.get("id"), + "scope": scope, + "attribute_id": attr, + "current_scaled": current_scaled, + "op": op, + "value_scaled": scaled_value, + }) + current_mzn_scaled = aggregated_mzn_scaled.get(attr) if scope == "GLOBAL" else current_scaled + if current_mzn_scaled is not None: + if not _check_op(float(current_mzn_scaled), op, float(scaled_value)): + mzn_scaled_bound_violations.append({ + "constraint_id": c.get("id"), + "scope": scope, + "attribute_id": attr, + "current_scaled": current_mzn_scaled, + "op": op, + "value_scaled": scaled_value, + }) + + elif kind == "DEPENDENCY": + dep_type = (c.get("type") or "").upper() + tasks = c.get("tasks") or [] + if len(tasks) < 2: + continue + providers = [] + missing = False + for t in tasks: + cand = selected_by_task.get(t) + if cand is None: + missing = True + break + providers.append(cand.get("provider_id")) + if missing: + notes.append({"constraint_id": c.get("id"), "reason": "missing_dependency_binding"}) + continue + + if dep_type == "SAME_PROVIDER": + for i in range(len(providers) - 1): + if providers[i] != providers[i + 1]: + dependency_violations.append({ + "constraint_id": c.get("id"), + "type": dep_type, + "tasks": tasks, + "providers": providers, + }) + break + elif dep_type == "DIFFERENT_PROVIDER": + for i in range(len(providers)): + for j in range(i + 1, len(providers)): + if providers[i] == providers[j]: + dependency_violations.append({ + "constraint_id": c.get("id"), + "type": dep_type, + "tasks": tasks, + "providers": providers, + }) + i = len(providers) + break + + for fid, ub in qos_ub.items(): + current = aggregated_mzn_scaled.get(fid) + if current is None: + continue + if float(current) > float(ub) + 1e-9: + qos_ub_violations.append({ + "attribute_id": fid, + "current_scaled": current, + "qos_ub": ub, + }) + + for node_id, vals in node_qos_mzn_scaled.items(): + kind = vals.get("kind") + for fid, ub in qos_ub.items(): + current = vals.get(fid) + if current is None: + continue + if float(current) > float(ub) + 1e-9: + qos_ub_node_violations.append({ + "node_id": node_id, + "node_kind": kind, + "attribute_id": fid, + "current_scaled": current, + "qos_ub": ub, + }) + + return { + "binding": binding, + "aggregated_features": aggregated, + "aggregated_features_scaled": aggregated_scaled, + "aggregated_features_mzn_scaled": aggregated_mzn_scaled, + "node_qos_mzn_scaled": node_qos_mzn_scaled, + "qos_ub": qos_ub, + "bound_violations": bound_violations, + "mzn_scaled_bound_violations": scaled_bound_violations, + "mzn_loop_scaled_bound_violations": mzn_scaled_bound_violations, + "qos_ub_violations": qos_ub_violations, + "qos_ub_node_violations": qos_ub_node_violations, + "dependency_violations": dependency_violations, + "notes": notes, + } + +def load_instances(): + """Load all JSON instances from the directory.""" + instances = [] + if not os.path.exists(INSTANCES_DIR): + print(colored(f"Directory {INSTANCES_DIR} does not exist.", "red")) + return [] + + files = sorted([f for f in os.listdir(INSTANCES_DIR) if f.endswith(".json")]) + for f in files: + with open(os.path.join(INSTANCES_DIR, f), 'r') as fd: + try: + data = json.load(fd) + instances.append({"filename": f, "data": data}) + except Exception as e: + print(colored(f"Error loading {f}: {e}", "red")) + return instances + +def solve(instance: Dict[str, Any], engine_id: str, options: Optional[Dict[str, Any]] = None) -> Tuple[int, Dict[str, Any], float]: + """Send request to gateway, poll if 202, return status, response, duration.""" + payload = { + "engine_id": engine_id, + "instance": instance, + "verbose": True # Enable diagnostics + } + if options: + payload["options"] = options + start = time.time() + try: + # Initial Request + resp = None + for attempt in range(2 + 1): + try: + resp = requests.post(GATEWAY_URL, json=payload, timeout=900) + if resp.status_code in (502, 503, 504): + if attempt >= 2: + return resp.status_code, {"error": resp.text}, time.time() - start + time.sleep(1) + continue + break + except requests.Timeout: + if attempt >= 2: + return 504, {"error": "Gateway timeout on initial request"}, time.time() - start + time.sleep(1) + except requests.ConnectionError: + if attempt >= 2: + return 503, {"error": "Gateway connection failed"}, time.time() - start + time.sleep(1) + + if resp is None: + return 503, {"error": "Gateway connection failed"}, time.time() - start + + if resp.status_code == 202: + job_id = resp.json().get("job_id") + # Poll loop with configurable or derived max duration + max_poll_seconds = 7200 + if max_poll_seconds <= 0: + if 1000 > 0: + max_poll_seconds = min(7200, max(300, int(1000 / 2000))) + else: + max_poll_seconds = 300 + start_poll = time.time() + while time.time() - start_poll < max_poll_seconds: + try: + poll_resp = requests.get(f"http://localhost:8000/v1/jobs/{job_id}", timeout=30) + if poll_resp.status_code == 200: + poll_data = poll_resp.json() + status = poll_data.get("status") + if status == "completed": + duration = time.time() - start + # Return the result which is inside the job result + return 200, poll_data.get("result", {}), duration + elif status == "failed": + duration = time.time() - start + return 500, {"error": poll_data.get("error"), "detail": poll_data.get("detail")}, duration + time.sleep(2) + except requests.RequestException: + time.sleep(2) + + # Timeout + duration = time.time() - start + return 408, {"error": "Timeout waiting for job completion", "job_id": job_id}, duration + + elif resp.status_code == 200: + duration = time.time() - start + data = resp.json() + # Normalise: if this is a JobResponse wrapper, extract .result + if "result" in data and "job_id" in data: + return 200, data.get("result", {}), duration + return 200, data, duration + else: + duration = time.time() - start + try: + return resp.status_code, resp.json(), duration + except: + return resp.status_code, {"error": resp.text}, duration + + except Exception as e: + duration = time.time() - start + return 500, {"error": str(e)}, duration + +def determine_result(obj_type, has_soft, mzn_s, rs_s, rs_resp=None, many_s=None, many_resp=None): + """Determine if the result is a PASS or FAIL based on expectations.""" + is_pass = False + msg = "" + + # Check if RS returned 200 but with no actual solutions (heuristic failure) + rs_has_solution = True + if rs_resp and rs_s in [200, 202]: + b = get_binding(rs_resp) + if b is None: + rs_has_solution = False + + if obj_type == "MANY": + # Expected: MZN/RS reject, Many-Heuristic solves with a non-empty binding set + many_has_solution = has_non_empty_binding_set(many_resp) if many_resp and many_s in [200, 202] else False + if mzn_s >= 400 and rs_s >= 400 and many_s in [200, 202]: + if many_has_solution: + is_pass = True + msg = "PASS (MZN/RS Reject, MANY Solve)" + else: + msg = "FAIL (MANY NoSol)" + else: + msg = f"FAIL (Exp MZN/RS Reject, MANY OK; got MZN:{mzn_s} RS:{rs_s} MANY:{many_s})" + + elif obj_type == "MULTI": + # Expected: All reject (>=400) + if mzn_s >= 400 and rs_s >= 400 and (many_s is None or many_s >= 400): + is_pass = True + msg = "PASS (All Rejected)" + else: + msg = f"FAIL (Exp Reject, got MZN:{mzn_s} RS:{rs_s} MANY:{many_s})" + + elif has_soft: + # Expected: MZN Reject (>=400), RS Solve (200/202) + if mzn_s >= 400 and rs_s in [200, 202]: + if rs_has_solution: + is_pass = True + msg = "PASS (MZN Reject, RS Solve)" + else: + is_pass = True # Still pass — RS is heuristic, no-solution is valid + msg = "PASS (MZN Reject, RS NoSol)" + else: + msg = f"FAIL (Exp MZN Fail/RS OK, got MZN:{mzn_s} RS:{rs_s})" + + else: # Single + Hard + # Expected: Both Solve + if mzn_s in [200, 202] and rs_s in [200, 202]: + if rs_has_solution: + is_pass = True + msg = "PASS (Both Solved)" + else: + is_pass = True # RS is heuristic — no-solution is acceptable + msg = "PASS (MZN Solved, RS NoSol)" + else: + msg = f"FAIL (Exp Both OK, got MZN:{mzn_s} RS:{rs_s})" + + return is_pass, msg + +def run_experiments(): + instances = load_instances() + print(colored(f"Found {len(instances)} instances. Starting experiments...", "cyan", attrs=["bold"])) + print(colored( + f"Configuration: Timeout=300s, Engines=MiniZinc,RandomSearch,ManyHeuristic, " + f"Iterations={DEFAULT_ITERATIONS_COUNT}, ManyIterations={MANY_ITERATIONS_COUNT}", + "cyan" + )) + + results = [] + + # Progress Bar using tqdm + # LIMIT FOR TESTING (User request: do not run all) + instances = instances[:100] + pbar = tqdm(instances, unit="inst") + + for item in pbar: + filename = item["filename"] + data = item["data"] + obj_type = data.get("objective", {}).get("type", "MONO") + constraints = data.get("constraints", []) + has_soft = any(not c.get("hard", True) for c in constraints) + + # Update description + short_name = (filename[:25] + '..') if len(filename) > 25 else filename + pbar.set_description(f"Processing {short_name}") + + # Run Engines + mzn_status, mzn_resp, mzn_time = solve( + data, + "minizinc-csp", + options={"iterations_count": DEFAULT_ITERATIONS_COUNT} + ) + rs_status, rs_resp, rs_time = solve( + data, + "random-search", + options={"iterations_count": DEFAULT_ITERATIONS_COUNT} + ) + many_status, many_resp, many_time = solve( + data, + "many-heuristic", + options={"iterations_count": MANY_ITERATIONS_COUNT} + ) + + # Analyze Result immediately for log + is_pass, msg = determine_result( + obj_type, + has_soft, + mzn_status, + rs_status, + rs_resp, + many_status, + many_resp + ) + + # Store result + mzn_binding = get_binding(mzn_resp) if mzn_resp and mzn_status in [200, 202] else None + rs_binding = get_binding(rs_resp) if rs_resp and rs_status in [200, 202] else None + mzn_no_solution_diag = None + if mzn_status in [200, 202] and mzn_binding is None and rs_binding is not None: + mzn_no_solution_diag = analyze_mzn_no_solution(data, rs_resp) + + results.append({ + "filename": filename, + "objective": obj_type, + "has_soft": has_soft, + "minizinc": {"status": mzn_status, "response": mzn_resp, "time": mzn_time}, + "random_search": {"status": rs_status, "response": rs_resp, "time": rs_time}, + "many_heuristic": {"status": many_status, "response": many_resp, "time": many_time}, + "mzn_no_solution_diag": mzn_no_solution_diag, + "is_pass": is_pass, + "msg": msg + }) + + # Print colored line above progress bar + color = "green" if is_pass else "red" + status_icon = "✓" if is_pass else "✗" + + # Determine specific reason color (e.g. Expected Fail vs Unexpected Fail) + # Using cyan for info on time + + tqdm.write( + colored(f"{status_icon} {filename}", color, attrs=["bold"]) + + f" | {msg} | " + + colored(f"MZN: {mzn_status} ({mzn_time:.1f}s)", "blue") + " | " + + colored(f"RS: {rs_status} ({rs_time:.1f}s)", "magenta") + " | " + + colored(f"MANY: {many_status} ({many_time:.1f}s)", "cyan") + ) + + generate_report(results) + print(colored(f"\nReport generated successfully at {REPORT_FILE}", "green", attrs=["bold"])) + +def get_binding(response): + """Effectively extracts the binding dictionary from a response.""" + if not response or "error" in response or "detail" in response: + return None + # Check top-level solutions (async/poll path) + solutions = response.get("solutions", []) + if solutions and len(solutions) > 0: + return solutions[0].get("binding") + # Check nested result.solutions (sync path — full JobResponse) + result = response.get("result") + if result and isinstance(result, dict): + # Check for error in provenance metadata + prov = result.get("provenance") or {} + meta = prov.get("metadata") or {} + if meta.get("error"): + return None + solutions = result.get("solutions", []) + if solutions and len(solutions) > 0: + return solutions[0].get("binding") + return None + + +def has_non_empty_binding_set(response): + """Return True if any solution contains a non-empty binding.""" + if not response or "error" in response or "detail" in response: + return False + + def extract_solutions(obj): + solutions = obj.get("solutions", []) if isinstance(obj, dict) else [] + if solutions: + return solutions + result = obj.get("result") if isinstance(obj, dict) else None + if isinstance(result, dict): + return result.get("solutions", []) + return [] + + for solution in extract_solutions(response): + binding = solution.get("binding") + if isinstance(binding, dict) and len(binding) > 0: + return True + return False + +def generate_report(results): + with open(REPORT_FILE, 'w') as f: + f.write("# Experiment Report\n\n") + f.write(f"**Generated**: {time.strftime('%Y-%m-%d %H:%M:%S')}\n\n") + + # Summary Statistics + total = len(results) + passed = sum(1 for r in results if r["is_pass"]) + failed = total - passed + + f.write(f"**Total**: {total} | **Passed**: {passed} | **Failed**: {failed}\n\n") + + # Progress Bar visual in MD + percent = (passed / total) * 100 if total > 0 else 0 + f.write(f"![Progress](https://geps.dev/progress/{int(percent)}?dangerColor=d9534f&warningColor=f0ad4e&successColor=5cb85c)\n\n") + + # Summary Table + f.write("## Summary\n\n") + f.write("| Instance | Obj | Soft | MiniZinc | RandomSearch | ManyHeuristic | Binding Match | Binding Space Size | Result |\n") + f.write("|---|---|---|---|---|---|---|---|---|\n") + + for r in results: + fname = r["filename"].replace(".json", "") + if len(fname) > 30: fname = fname[:27] + "..." + + # Status Icons + mzn_s = r["minizinc"]["status"] + rs_s = r["random_search"]["status"] + many_s = r["many_heuristic"]["status"] + + mzn_icon = "🟢" if mzn_s in [200, 202] else "🔴" + rs_icon = "🟢" if rs_s in [200, 202] else "🔴" + many_icon = "🟢" if many_s in [200, 202] else "🔴" + + res_icon = "✅" if r["is_pass"] else "❌" + + # Binding Match Logic + binding_match = "" + + # Compare if BOTH engines returned a valid response (200 or 202) + if mzn_s in [200, 202] and rs_s in [200, 202]: + b_mzn = get_binding(r["minizinc"]["response"]) + b_rs = get_binding(r["random_search"]["response"]) + + if b_mzn is not None and b_rs is not None: + # Determine equality + # Bindings are dicts {task_id: candidate_id}, direct comparison works + if b_mzn == b_rs: + binding_match = "✅ MATCH" + else: + binding_match = "⚠️ DIFF" + elif b_mzn is None and b_rs is None: + binding_match = "✅ No Sol" + elif b_mzn is None: + binding_match = "⚠️ MZN NoSol" + elif b_rs is None: + binding_match = "⚠️ RS NoSol" + else: + binding_match = "❓ ERR" + else: + binding_match = "-" # N/A if failed or rejected + + # Binding Space Size Extraction + binding_space_size = "-" + + # Try to get from MiniZinc result first + if r["minizinc"]["response"] and "diagnostics" in r["minizinc"]["response"]: + diag = r["minizinc"]["response"]["diagnostics"] + if diag and "binding_space" in diag: + binding_space_size = diag["binding_space"]["cardinality"] + + # If not found, try Random Search + if binding_space_size == "-" and r["random_search"]["response"] and "diagnostics" in r["random_search"]["response"]: + diag = r["random_search"]["response"]["diagnostics"] + if diag and "binding_space" in diag: + binding_space_size = diag["binding_space"]["cardinality"] + + # Random Search es heurístico: una diferencia de binding no es un fallo "requerido". + if binding_match == "⚠️ DIFF": + binding_match = "⚠️ DIFF (HEUR)" + + f.write(f"| {fname} | {r['objective']} | {r['has_soft']} | {mzn_icon} {mzn_s} | {rs_icon} {rs_s} | {many_icon} {many_s} | {binding_match} | {binding_space_size} | {res_icon} {r['msg']} |\n") + + f.write("\n## Detailed Results\n\n") + + for r in results: + fname = r["filename"] + pass_badge = "![Pass](https://img.shields.io/badge/Result-PASS-success)" if r["is_pass"] else "![Fail](https://img.shields.io/badge/Result-FAIL-critical)" + + f.write(f"### {fname} {pass_badge}\n\n") + f.write(f"- **Objective**: `{r['objective']}`\n") + f.write(f"- **Soft Constraints**: `{r['has_soft']}`\n\n") + + # Columns + f.write("| Engine | Status | Time | Result |\n") + f.write("|---|---|---|---|\n") + + def row(name, d): + s = d["status"] + t = d["time"] + icon = "🟢" if s in [200, 202] else "🔴" + return f"| **{name}** | {icon} {s} | {t:.2f}s | See below |" + + f.write(row("MiniZinc CSP", r["minizinc"]) + "\n") + f.write(row("Random Search", r["random_search"]) + "\n\n") + f.write(row("Many Heuristic", r["many_heuristic"]) + "\n\n") + + f.write("
View Engine Responses\n\n") + + def print_details(name, d): + f.write(f"#### {name}\n") + resp = d["response"] + + # Check for solutions/binding + solutions = resp.get("solutions", []) + if solutions: + binding = solutions[0].get("binding", {}) + f.write("**Binding Solution**:\n") + f.write("```json\n") + f.write(json.dumps(binding, indent=2)) + f.write("\n```\n") + + agg = solutions[0].get("aggregated_features", {}) + if agg: + f.write("**Aggregated Features**:\n") + f.write("```json\n") + f.write(json.dumps(agg, indent=2)) + f.write("\n```\n") + elif "error" in resp: + f.write(f"**Error**:\n```json\n{json.dumps(resp, indent=2)}\n```\n") + else: + f.write(f"**Response**:\n```json\n{json.dumps(resp, indent=2)}\n```\n") + + print_details("MiniZinc CSP", r["minizinc"]) + if r.get("mzn_no_solution_diag"): + f.write("**MiniZinc No-Solution Analysis (based on RS binding)**:\n") + f.write("```json\n") + f.write(json.dumps(r["mzn_no_solution_diag"], indent=2)) + f.write("\n```\n") + f.write("\n---\n") + print_details("Random Search", r["random_search"]) + f.write("\n---\n") + print_details("Many Heuristic", r["many_heuristic"]) + + f.write("\n
\n\n---\n") + +if __name__ == "__main__": + run_experiments() diff --git a/frontend/package.json b/frontend/package.json index bb7761b..bd589b3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,8 +16,12 @@ "@uiw/react-codemirror": "^4.25.4", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", + "mermaid": "^11.12.0", + "lucide-react": "^0.468.0", "react": "^19.2.0", "react-dom": "^19.2.0", + "react-zoom-pan-pinch": "^3.7.0", + "recharts": "^2.15.4", "react-router-dom": "^7.13.0" }, "devDependencies": { diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 5e6167f..c44e957 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -26,6 +26,12 @@ importers: ajv-formats: specifier: ^3.0.1 version: 3.0.1(ajv@8.17.1) + lucide-react: + specifier: ^0.468.0 + version: 0.468.0(react@19.2.3) + mermaid: + specifier: ^11.12.0 + version: 11.12.2 react: specifier: ^19.2.0 version: 19.2.3 @@ -35,6 +41,12 @@ importers: react-router-dom: specifier: ^7.13.0 version: 7.13.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react-zoom-pan-pinch: + specifier: ^3.7.0 + version: 3.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + recharts: + specifier: ^2.15.4 + version: 2.15.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) devDependencies: '@eslint/js': specifier: ^9.39.1 @@ -75,6 +87,9 @@ importers: packages: + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + '@babel/code-frame@7.28.6': resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} engines: {node: '>=6.9.0'} @@ -162,6 +177,24 @@ packages: resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} engines: {node: '>=6.9.0'} + '@braintree/sanitize-url@7.1.2': + resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} + + '@chevrotain/cst-dts-gen@11.0.3': + resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==} + + '@chevrotain/gast@11.0.3': + resolution: {integrity: sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==} + + '@chevrotain/regexp-to-ast@11.0.3': + resolution: {integrity: sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==} + + '@chevrotain/types@11.0.3': + resolution: {integrity: sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==} + + '@chevrotain/utils@11.0.3': + resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} + '@codemirror/autocomplete@6.20.0': resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==} @@ -399,6 +432,12 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@3.1.0': + resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -430,6 +469,9 @@ packages: '@marijn/find-cluster-break@1.0.2': resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} + '@mermaid-js/parser@0.6.3': + resolution: {integrity: sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==} + '@rolldown/pluginutils@1.0.0-beta.53': resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} @@ -570,9 +612,105 @@ packages: '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -587,6 +725,9 @@ packages: '@types/react@19.2.8': resolution: {integrity: sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@typescript-eslint/eslint-plugin@8.53.1': resolution: {integrity: sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -734,6 +875,18 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chevrotain-allstar@0.3.1: + resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} + peerDependencies: + chevrotain: ^11.0.0 + + chevrotain@11.0.3: + resolution: {integrity: sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + codemirror@6.0.2: resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} @@ -744,9 +897,20 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -754,6 +918,12 @@ packages: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} @@ -764,6 +934,165 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.33.1: + resolution: {integrity: sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.13: + resolution: {integrity: sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==} + + dayjs@1.11.19: + resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -773,9 +1102,21 @@ packages: supports-color: optional: true + decimal.js-light@2.5.1: + resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + + dompurify@3.3.1: + resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==} + electron-to-chromium@1.5.267: resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} @@ -845,9 +1186,16 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-equals@5.4.0: + resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} + engines: {node: '>=6.0.0'} + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -902,6 +1250,9 @@ packages: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -912,6 +1263,10 @@ packages: hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -928,6 +1283,13 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -968,9 +1330,26 @@ packages: engines: {node: '>=6'} hasBin: true + katex@0.16.28: + resolution: {integrity: sha512-YHzO7721WbmAL6Ov1uzN/l5mY5WWWhJBSW+jq4tkfZfsxmo1hu6frS0EOswvjBUnWE6NtjEs48SFn5CQESRLZg==} + hasBin: true + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + + langium@3.3.1: + resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==} + engines: {node: '>=16.0.0'} + + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -979,12 +1358,38 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + + lodash-es@4.17.23: + resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash@4.17.23: + resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@0.468.0: + resolution: {integrity: sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc + + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + + mermaid@11.12.2: + resolution: {integrity: sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -992,6 +1397,9 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + mlly@1.8.0: + resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1006,6 +1414,10 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1018,10 +1430,16 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -1030,6 +1448,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1037,6 +1458,15 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -1045,6 +1475,9 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1054,6 +1487,12 @@ packages: peerDependencies: react: ^19.2.3 + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-refresh@0.18.0: resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} engines: {node: '>=0.10.0'} @@ -1075,10 +1514,39 @@ packages: react-dom: optional: true + react-smooth@4.0.4: + resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + + react-zoom-pan-pinch@3.7.0: + resolution: {integrity: sha512-UmReVZ0TxlKzxSbYiAj+LeGRW8s8LraAFTXRAxzMYnNRgGPsxCudwZKVkjvGmjtx7SW/hZamt69NUmGf4xrkXA==} + engines: {node: '>=8', npm: '>=5'} + peerDependencies: + react: '*' + react-dom: '*' + react@19.2.3: resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} engines: {node: '>=0.10.0'} + recharts-scale@0.4.5: + resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} + + recharts@2.15.4: + resolution: {integrity: sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==} + engines: {node: '>=14'} + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} @@ -1087,11 +1555,23 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rollup@4.55.2: resolution: {integrity: sha512-PggGy4dhwx5qaW+CKBilA/98Ql9keyfnb7lh4SR6shQ91QQQi1ORJ1v4UinkdP2i87OBs9AQFooQylcrrRfIcg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -1126,10 +1606,20 @@ packages: style-mod@4.1.3: resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} @@ -1140,6 +1630,10 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -1156,6 +1650,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} @@ -1168,6 +1665,13 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + + victory-vendor@36.9.2: + resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + vite@7.3.1: resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1208,6 +1712,26 @@ packages: yaml: optional: true + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-uri@3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} @@ -1238,6 +1762,11 @@ packages: snapshots: + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.6.0 + tinyexec: 1.0.2 + '@babel/code-frame@7.28.6': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -1352,6 +1881,25 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@braintree/sanitize-url@7.1.2': {} + + '@chevrotain/cst-dts-gen@11.0.3': + dependencies: + '@chevrotain/gast': 11.0.3 + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + + '@chevrotain/gast@11.0.3': + dependencies: + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + + '@chevrotain/regexp-to-ast@11.0.3': {} + + '@chevrotain/types@11.0.3': {} + + '@chevrotain/utils@11.0.3': {} + '@codemirror/autocomplete@6.20.0': dependencies: '@codemirror/language': 6.12.1 @@ -1545,6 +2093,14 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@iconify/types@2.0.0': {} + + '@iconify/utils@3.1.0': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@iconify/types': 2.0.0 + mlly: 1.8.0 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -1582,6 +2138,10 @@ snapshots: '@marijn/find-cluster-break@1.0.2': {} + '@mermaid-js/parser@0.6.3': + dependencies: + langium: 3.3.1 + '@rolldown/pluginutils@1.0.0-beta.53': {} '@rollup/rollup-android-arm-eabi@4.55.2': @@ -1680,8 +2240,127 @@ snapshots: dependencies: '@babel/types': 7.28.6 + '@types/d3-array@3.2.2': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.2 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + '@types/estree@1.0.8': {} + '@types/geojson@7946.0.16': {} + '@types/json-schema@7.0.15': {} '@types/node@24.10.9': @@ -1696,6 +2375,9 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/trusted-types@2.0.7': + optional: true + '@typescript-eslint/eslint-plugin@8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -1886,6 +2568,22 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chevrotain-allstar@0.3.1(chevrotain@11.0.3): + dependencies: + chevrotain: 11.0.3 + lodash-es: 4.17.23 + + chevrotain@11.0.3: + dependencies: + '@chevrotain/cst-dts-gen': 11.0.3 + '@chevrotain/gast': 11.0.3 + '@chevrotain/regexp-to-ast': 11.0.3 + '@chevrotain/types': 11.0.3 + '@chevrotain/utils': 11.0.3 + lodash-es: 4.17.21 + + clsx@2.1.1: {} + codemirror@6.0.2: dependencies: '@codemirror/autocomplete': 6.20.0 @@ -1902,12 +2600,26 @@ snapshots: color-name@1.1.4: {} + commander@7.2.0: {} + + commander@8.3.0: {} + concat-map@0.0.1: {} + confbox@0.1.8: {} + convert-source-map@2.0.0: {} cookie@1.1.1: {} + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + crelt@1.0.6: {} cross-spawn@7.0.6: @@ -1918,12 +2630,213 @@ snapshots: csstype@3.2.3: {} + cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.33.1 + + cytoscape-fcose@2.2.0(cytoscape@3.33.1): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.33.1 + + cytoscape@3.33.1: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.2: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.2 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.13: + dependencies: + d3: 7.9.0 + lodash-es: 4.17.23 + + dayjs@1.11.19: {} + debug@4.4.3: dependencies: ms: 2.1.3 + decimal.js-light@2.5.1: {} + deep-is@0.1.4: {} + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + + dom-helpers@5.2.1: + dependencies: + '@babel/runtime': 7.28.6 + csstype: 3.2.3 + + dompurify@3.3.1: + optionalDependencies: + '@types/trusted-types': 2.0.7 + electron-to-chromium@1.5.267: {} esbuild@0.27.2: @@ -2040,8 +2953,12 @@ snapshots: esutils@2.0.3: {} + eventemitter3@4.0.7: {} + fast-deep-equal@3.1.3: {} + fast-equals@5.4.0: {} + fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -2081,6 +2998,8 @@ snapshots: globals@16.5.0: {} + hachure-fill@0.5.2: {} + has-flag@4.0.0: {} hermes-estree@0.25.1: {} @@ -2089,6 +3008,10 @@ snapshots: dependencies: hermes-estree: 0.25.1 + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ignore@5.3.2: {} ignore@7.0.5: {} @@ -2100,6 +3023,10 @@ snapshots: imurmurhash@0.1.4: {} + internmap@1.0.1: {} + + internmap@2.0.3: {} + is-extglob@2.1.1: {} is-glob@4.0.3: @@ -2126,10 +3053,28 @@ snapshots: json5@2.2.3: {} + katex@0.16.28: + dependencies: + commander: 8.3.0 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 + khroma@2.1.0: {} + + langium@3.3.1: + dependencies: + chevrotain: 11.0.3 + chevrotain-allstar: 0.3.1(chevrotain@11.0.3) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -2139,12 +3084,51 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash-es@4.17.21: {} + + lodash-es@4.17.23: {} + lodash.merge@4.6.2: {} + lodash@4.17.23: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + lru-cache@5.1.1: dependencies: yallist: 3.1.1 + lucide-react@0.468.0(react@19.2.3): + dependencies: + react: 19.2.3 + + marked@16.4.2: {} + + mermaid@11.12.2: + dependencies: + '@braintree/sanitize-url': 7.1.2 + '@iconify/utils': 3.1.0 + '@mermaid-js/parser': 0.6.3 + '@types/d3': 7.4.3 + cytoscape: 3.33.1 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.1) + cytoscape-fcose: 2.2.0(cytoscape@3.33.1) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.13 + dayjs: 1.11.19 + dompurify: 3.3.1 + katex: 0.16.28 + khroma: 2.1.0 + lodash-es: 4.17.23 + marked: 16.4.2 + roughjs: 4.6.6 + stylis: 4.3.6 + ts-dedent: 2.2.0 + uuid: 11.1.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -2153,6 +3137,13 @@ snapshots: dependencies: brace-expansion: 2.0.2 + mlly@1.8.0: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.3 + ms@2.1.3: {} nanoid@3.3.11: {} @@ -2161,6 +3152,8 @@ snapshots: node-releases@2.0.27: {} + object-assign@4.1.1: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -2178,18 +3171,37 @@ snapshots: dependencies: p-limit: 3.1.0 + package-manager-detector@1.6.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 + path-data-parser@0.1.0: {} + path-exists@4.0.0: {} path-key@3.1.1: {} + pathe@2.0.3: {} + picocolors@1.1.1: {} picomatch@4.0.3: {} + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.0 + pathe: 2.0.3 + + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -2198,6 +3210,12 @@ snapshots: prelude-ls@1.2.1: {} + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + punycode@2.3.1: {} react-dom@19.2.3(react@19.2.3): @@ -2205,6 +3223,10 @@ snapshots: react: 19.2.3 scheduler: 0.27.0 + react-is@16.13.1: {} + + react-is@18.3.1: {} + react-refresh@0.18.0: {} react-router-dom@7.13.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): @@ -2221,12 +3243,53 @@ snapshots: optionalDependencies: react-dom: 19.2.3(react@19.2.3) + react-smooth@4.0.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + fast-equals: 5.4.0 + prop-types: 15.8.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react-transition-group: 4.4.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + + react-transition-group@4.4.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + '@babel/runtime': 7.28.6 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + react-zoom-pan-pinch@3.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react@19.2.3: {} + recharts-scale@0.4.5: + dependencies: + decimal.js-light: 2.5.1 + + recharts@2.15.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + clsx: 2.1.1 + eventemitter3: 4.0.7 + lodash: 4.17.23 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react-is: 18.3.1 + react-smooth: 4.0.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + recharts-scale: 0.4.5 + tiny-invariant: 1.3.3 + victory-vendor: 36.9.2 + require-from-string@2.0.2: {} resolve-from@4.0.0: {} + robust-predicates@3.0.2: {} + rollup@4.55.2: dependencies: '@types/estree': 1.0.8 @@ -2258,6 +3321,17 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.55.2 fsevents: 2.3.3 + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + + rw@1.3.3: {} + + safer-buffer@2.1.2: {} + scheduler@0.27.0: {} semver@6.3.1: {} @@ -2278,10 +3352,16 @@ snapshots: style-mod@4.1.3: {} + stylis@4.3.6: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 + tiny-invariant@1.3.3: {} + + tinyexec@1.0.2: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -2291,6 +3371,8 @@ snapshots: dependencies: typescript: 5.9.3 + ts-dedent@2.2.0: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -2308,6 +3390,8 @@ snapshots: typescript@5.9.3: {} + ufo@1.6.3: {} + undici-types@7.16.0: {} update-browserslist-db@1.2.3(browserslist@4.28.1): @@ -2320,6 +3404,25 @@ snapshots: dependencies: punycode: 2.3.1 + uuid@11.1.0: {} + + victory-vendor@36.9.2: + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-ease': 3.0.2 + '@types/d3-interpolate': 3.0.4 + '@types/d3-scale': 4.0.9 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-timer': 3.0.2 + d3-array: 3.2.4 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-timer: 3.0.1 + vite@7.3.1(@types/node@24.10.9): dependencies: esbuild: 0.27.2 @@ -2332,6 +3435,23 @@ snapshots: '@types/node': 24.10.9 fsevents: 2.3.3 + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-uri@3.0.8: {} + w3c-keyname@2.2.8: {} which@2.0.2: diff --git a/frontend/src/App-old.css b/frontend/src/App-old.css deleted file mode 100644 index b9d355d..0000000 --- a/frontend/src/App-old.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/frontend/src/App-old.tsx b/frontend/src/App-old.tsx deleted file mode 100644 index 168a6c8..0000000 --- a/frontend/src/App-old.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { BrowserRouter, Routes, Route } from 'react-router-dom'; -import { ThemeProvider } from './contexts/ThemeContext'; -import { Navigation } from './components/Navigation/Navigation'; -import { Home } from './pages/Home/Home'; -import { Playground } from './pages/Playground/Playground'; -import { Engines } from './pages/Engines/Engines'; -import { Schemas } from './pages/Schemas/Schemas'; -import './styles/globals.css'; - -function App() { - return ( - - -
- -
- - } /> - } /> - } /> - } /> - -
-
-
-
- ); -} - -export default App; diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 3143b32..b0f6347 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -6,6 +6,8 @@ export interface Engine { active?: boolean; } +export type EngineDefaultOptions = Record; + export interface ValidationViolation { code: string; message: string; @@ -48,6 +50,29 @@ export interface AnalyzeRequest { verbose?: boolean; } +export interface BindingSpaceRequest { + engine_id: string; + instance: any; + offset?: number; + limit?: number; +} + +export interface BindingSpacePage { + total_combinations: string; + offset: number; + limit: number; + bindings: Array>; +} + +class HttpError extends Error { + status: number; + + constructor(status: number, statusText: string) { + super(`HTTP ${status}: ${statusText}`); + this.status = status; + } +} + class ApiClient { private baseUrl: string; @@ -57,36 +82,116 @@ class ApiClient { private async request( endpoint: string, - options: RequestInit = {} + options: RequestInit = {}, + timeoutMs?: number ): Promise { const url = `${this.baseUrl}${endpoint}`; - - const response = await fetch(url, { - ...options, - headers: { - 'Content-Type': 'application/json', - ...options.headers, - }, - }); + const controller = new AbortController(); + const timeoutId = timeoutMs ? setTimeout(() => controller.abort(), timeoutMs) : undefined; + + try { + const response = await fetch(url, { + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers, + }, + signal: controller.signal, + }); - // Handle validation errors (422) specially - if (response.status === 422) { - const errorData = await response.json(); - // Return the error data as-is so the caller can handle violations - return errorData as T; + // Handle validation errors (422) specially + if (response.status === 422) { + const errorData = await response.json(); + // Return the error data as-is so the caller can handle violations + return errorData as T; + } + + if (!response.ok) { + throw new HttpError(response.status, response.statusText); + } + + return response.json(); + } catch (error: any) { + if (error?.name === 'AbortError') { + throw new Error('Request timed out'); + } + throw error; + } finally { + if (timeoutId) { + clearTimeout(timeoutId); + } + } + } + + private async requestText( + endpoint: string, + options: RequestInit = {}, + timeoutMs?: number + ): Promise { + const url = `${this.baseUrl}${endpoint}`; + const controller = new AbortController(); + const timeoutId = timeoutMs ? setTimeout(() => controller.abort(), timeoutMs) : undefined; + + try { + const response = await fetch(url, { + ...options, + headers: { + ...options.headers, + }, + signal: controller.signal, + }); + + if (!response.ok) { + throw new HttpError(response.status, response.statusText); + } + + return response.text(); + } catch (error: any) { + if (error?.name === 'AbortError') { + throw new Error('Request timed out'); + } + throw error; + } finally { + if (timeoutId) { + clearTimeout(timeoutId); + } } + } + + private async requestWithRetry( + endpoint: string, + options: RequestInit, + timeoutMs: number, + retries: number + ): Promise { + for (let attempt = 0; attempt <= retries; attempt += 1) { + try { + return await this.request(endpoint, options, timeoutMs); + } catch (error) { + const isHttpError = error instanceof HttpError; + const shouldRetry = isHttpError + ? [502, 503, 504].includes(error.status) + : true; - if (!response.ok) { - throw new Error(`HTTP ${response.status}: ${response.statusText}`); + if (attempt >= retries || !shouldRetry) { + throw error; + } + + await new Promise((resolve) => setTimeout(resolve, 1000)); + } } - return response.json(); + throw new Error('Request failed after retries'); } async getEngines(): Promise { return this.request('/v1/engines'); } + async getEngineDefaultOptions(engineId: string): Promise { + return this.request(`/v1/engines/${engineId}/options/defaults`); + } + async getGeneralSchema(): Promise { return this.request('/v1/schemas/general'); } @@ -95,33 +200,70 @@ class ApiClient { return this.request(`/v1/schemas/${engineId}`); } + async getGeneralSchemaModel(): Promise { + try { + return await this.requestText('/v1/schemas/general/model'); + } catch (error) { + if (error instanceof HttpError && error.status === 404) { + return null; + } + throw error; + } + } + + async getEngineSchemaModel(engineId: string): Promise { + try { + return await this.requestText(`/v1/schemas/${engineId}/model`); + } catch (error) { + if (error instanceof HttpError && error.status === 404) { + return null; + } + throw error; + } + } + async solve(request: SolveRequest): Promise { - return this.request('/v1/solve', { - method: 'POST', - body: JSON.stringify(request), - }); + return this.requestWithRetry( + '/v1/solve', + { + method: 'POST', + body: JSON.stringify(request), + }, + 900000, + 2 + ); } async analyze(request: AnalyzeRequest): Promise { return this.request('/v1/analyze', { method: 'POST', body: JSON.stringify(request), - }); + }, 900000); } - async getJobStatus(jobId: string): Promise { - return this.request(`/v1/jobs/${jobId}`); + async getJobStatus(jobId: string, timeoutMs: number = 30000): Promise { + return this.request(`/v1/jobs/${jobId}`, {}, timeoutMs); } async pollJob( jobId: string, onUpdate?: (status: JobStatus) => void, - interval: number = 1000 + interval: number = 2000 ): Promise { return new Promise((resolve, reject) => { + const start = Date.now(); + let consecutiveErrors = 0; + const MAX_CONSECUTIVE_ERRORS = 3; + const poll = async () => { try { - const status = await this.getJobStatus(jobId); + if (Date.now() - start > 7200000) { + reject(new Error('Polling timed out')); + return; + } + + const status = await this.getJobStatus(jobId, 30000); + consecutiveErrors = 0; // Reset on success if (onUpdate) { onUpdate(status); @@ -134,14 +276,40 @@ class ApiClient { } else { setTimeout(poll, interval); } - } catch (error) { - reject(error); + } catch (error: any) { + consecutiveErrors++; + + // If the job is not found (404), it likely completed synchronously + // or the engine restarted. Don't retry indefinitely. + if (error instanceof HttpError && error.status === 404) { + reject(new Error( + 'The job could not be found on the server. ' + + 'It may have completed synchronously or the engine may have restarted.' + )); + return; + } + + // For transient errors, allow a few retries before giving up + if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) { + reject(error); + return; + } + + // Retry with a longer backoff + setTimeout(poll, interval * 2); } }; poll(); }); } + + async exploreBindingSpace(request: BindingSpaceRequest): Promise { + return this.request('/v1/analyze/binding-space', { + method: 'POST', + body: JSON.stringify(request), + }); + } } export const apiClient = new ApiClient(); diff --git a/frontend/src/api/schemaModels.ts b/frontend/src/api/schemaModels.ts new file mode 100644 index 0000000..381c16a --- /dev/null +++ b/frontend/src/api/schemaModels.ts @@ -0,0 +1,33 @@ +import { apiClient } from './client'; + +class SchemaModelService { + private generalModel: string | null | undefined; + private engineModels = new Map(); + + async getGeneralModel(): Promise { + if (this.generalModel !== undefined) { + return this.generalModel; + } + + const model = await apiClient.getGeneralSchemaModel(); + this.generalModel = model; + return model; + } + + async getEngineModel(engineId: string): Promise { + if (this.engineModels.has(engineId)) { + return this.engineModels.get(engineId) ?? null; + } + + const model = await apiClient.getEngineSchemaModel(engineId); + this.engineModels.set(engineId, model); + return model; + } + + clearCache(): void { + this.generalModel = undefined; + this.engineModels.clear(); + } +} + +export const schemaModelService = new SchemaModelService(); diff --git a/frontend/src/components/BindingSpaceExplorer/BindingSpaceExplorer.css b/frontend/src/components/BindingSpaceExplorer/BindingSpaceExplorer.css new file mode 100644 index 0000000..cc577af --- /dev/null +++ b/frontend/src/components/BindingSpaceExplorer/BindingSpaceExplorer.css @@ -0,0 +1,562 @@ +.binding-space-explorer { + width: 100%; + padding: var(--space-4); + background: var(--color-bg-secondary); + border-radius: var(--radius-lg); + border: 1px solid var(--color-border); +} + +.summary-cards { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: var(--space-3); + margin-bottom: var(--space-6); +} + +.summary-card { + background: var(--color-bg-elevated); + padding: var(--space-4); + border-radius: var(--radius-md); + border: 1px solid var(--color-border); + display: flex; + align-items: center; + gap: var(--space-3); + transition: all var(--transition-fast); +} + +.summary-card:hover { + border-color: var(--color-border-hover); + transform: translateY(-2px); + box-shadow: var(--shadow-md); +} + +.summary-card.complexity { + border-width: 2px; +} + +.card-icon { + font-size: 2rem; + line-height: 1; + flex-shrink: 0; +} + +.card-content { + display: flex; + flex-direction: column; + gap: var(--space-1); + flex: 1; + min-width: 0; +} + +.card-label { + color: var(--color-text-tertiary); + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.05em; + font-weight: 600; +} + +.card-value { + color: var(--color-text-primary); + font-size: 1.5rem; + font-weight: 700; + line-height: 1; + overflow: hidden; + text-overflow: ellipsis; +} + +.chart-section { + margin-bottom: var(--space-6); +} + +.section-title { + color: var(--color-text-primary); + font-size: 1.125rem; + font-weight: 600; + margin: 0 0 var(--space-4) 0; + padding-bottom: var(--space-2); + border-bottom: 2px solid var(--color-border); +} + +.binding-tooltip { + background: var(--color-bg-elevated); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + padding: var(--space-2) var(--space-3); + box-shadow: var(--shadow-lg); +} + +.tooltip-title { + color: var(--color-text-primary); + font-weight: 600; + margin: 0 0 var(--space-1) 0; + font-size: 0.875rem; +} + +.tooltip-count { + color: var(--color-text-secondary); + margin: 0; + font-size: 0.8125rem; +} + +.insights-section { + background: var(--color-bg-elevated); + padding: var(--space-4); + border-radius: var(--radius-md); + border: 1px solid var(--color-border); +} + +.insights-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + gap: var(--space-3); + margin-top: var(--space-3); +} + +.insight-card { + display: flex; + flex-direction: column; + gap: var(--space-1); + padding: var(--space-3); + background: var(--color-bg-secondary); + border-radius: var(--radius-md); + border: 1px solid var(--color-border); + transition: all var(--transition-fast); +} + +.insight-card:hover { + border-color: var(--color-border-hover); + box-shadow: var(--shadow-sm); +} + +.insight-label { + color: var(--color-text-secondary); + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.insight-value { + color: var(--color-text-primary); + font-size: 1.25rem; + font-weight: 700; +} + +/* Responsive adjustments */ +@media (max-width: 768px) { + .binding-space-explorer { + padding: var(--space-3); + } + + .summary-cards { + grid-template-columns: 1fr; + gap: var(--space-2); + } + + .summary-card { + padding: var(--space-3); + } + + .card-icon { + font-size: 1.75rem; + } + + .card-value { + font-size: 1.25rem; + } + + .section-title { + font-size: 1rem; + } + + .insights-grid { + grid-template-columns: 1fr; + gap: var(--space-2); + } + + .insight-value { + font-size: 1.125rem; + } +} + +/* Bindings Explorer Section */ +.bindings-explorer-section { + margin-top: var(--space-6); + padding: var(--space-4); + background: var(--color-bg-elevated); + border-radius: var(--radius-md); + border: 1px solid var(--color-border); +} + +.explorer-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--space-4); + gap: var(--space-4); + flex-wrap: wrap; +} + +.search-box { + position: relative; + flex: 1; + max-width: 400px; + min-width: 250px; +} + +.search-icon { + position: absolute; + left: var(--space-3); + top: 50%; + transform: translateY(-50%); + color: var(--color-text-tertiary); + pointer-events: none; + z-index: 1; +} + +.search-input { + width: 100%; + padding: var(--space-2) var(--space-3) var(--space-2) calc(var(--space-3) + 18px + var(--space-2)); + background: var(--color-bg-secondary); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + color: var(--color-text-primary); + font-size: 0.875rem; + transition: all var(--transition-fast); +} + +.search-input:focus { + outline: none; + border-color: var(--color-accent); + box-shadow: 0 0 0 3px var(--color-accent-subtle); +} + +.search-input::placeholder { + color: var(--color-text-tertiary); +} + +.error-message { + padding: var(--space-3); + margin-bottom: var(--space-4); + background: var(--color-error-bg); + border: 1px solid var(--color-error); + border-radius: var(--radius-md); + color: var(--color-error-text); + font-size: 0.875rem; +} + +.loading-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: var(--space-12); + gap: var(--space-4); + color: var(--color-text-secondary); +} + +.spinner { + animation: spin 1s linear infinite; +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +.bindings-table-wrapper { + overflow-x: auto; + margin-bottom: var(--space-4); + border-radius: var(--radius-md); + border: 1px solid var(--color-border); +} + +.bindings-table { + width: 100%; + border-collapse: collapse; + background: var(--color-bg-secondary); + font-size: 0.8125rem; +} + +.bindings-table thead { + background: var(--color-bg-tertiary); + position: sticky; + top: 0; + z-index: 10; +} + +.bindings-table th { + padding: var(--space-3); + text-align: left; + color: var(--color-text-primary); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + font-size: 0.6875rem; + white-space: nowrap; +} + +.binding-index { + width: 60px; + text-align: center !important; +} + +.task-column { + min-width: 120px; +} + +.actions-column { + width: 100px; + text-align: center !important; +} + +.bindings-table tbody tr { + border-top: 1px solid var(--color-border); + transition: all var(--transition-fast); +} + +.binding-row { + cursor: pointer; +} + +.binding-row:hover { + background: var(--color-bg-elevated); +} + +.binding-row.selected { + background: var(--color-accent-subtle); + border-left: 3px solid var(--color-accent); +} + +.bindings-table td { + padding: var(--space-3); + color: var(--color-text-secondary); +} + +.candidate-cell { + text-align: center; +} + +.candidate-badge { + display: inline-block; + padding: var(--space-1) var(--space-2); + background: var(--color-bg-tertiary); + border-radius: var(--radius-sm); + font-size: 0.75rem; + font-weight: 500; + color: var(--color-text-primary); + font-family: var(--font-mono); +} + +.empty-state { + text-align: center; + padding: var(--space-10) var(--space-4) !important; + color: var(--color-text-tertiary); + font-style: italic; +} + +.view-button { + padding: var(--space-1) var(--space-3); + background: var(--color-accent); + border: none; + border-radius: var(--radius-sm); + color: #fff; + font-size: 0.75rem; + font-weight: 600; + cursor: pointer; + transition: all var(--transition-fast); +} + +.view-button:hover { + background: var(--color-accent-hover); + transform: translateY(-1px); + box-shadow: var(--shadow-md); +} + +/* Pagination */ +.pagination { + display: flex; + justify-content: space-between; + align-items: center; + padding: var(--space-4); + background: var(--color-bg-secondary); + border-top: 1px solid var(--color-border); + border-radius: 0 0 var(--radius-md) var(--radius-md); + flex-wrap: wrap; + gap: var(--space-4); +} + +.pagination-info { + color: var(--color-text-secondary); + font-size: 0.8125rem; +} + +.pagination-controls { + display: flex; + align-items: center; + gap: var(--space-2); +} + +.page-button { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + background: var(--color-bg-elevated); + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); + color: var(--color-text-secondary); + cursor: pointer; + transition: all var(--transition-fast); +} + +.page-button:hover:not(:disabled) { + background: var(--color-bg-tertiary); + border-color: var(--color-border-hover); + color: var(--color-text-primary); +} + +.page-button:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +.page-indicator { + padding: 0 var(--space-3); + color: var(--color-text-primary); + font-size: 0.8125rem; + font-weight: 500; + white-space: nowrap; +} + +/* Binding Detail */ +.binding-detail { + margin-top: var(--space-6); + padding: var(--space-4); + background: var(--color-bg-elevated); + border-radius: var(--radius-md); + border: 1px solid var(--color-border); +} + +.binding-detail-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: var(--space-3); + margin-top: var(--space-3); +} + +.binding-detail-item { + display: flex; + align-items: center; + gap: var(--space-3); + padding: var(--space-3); + background: var(--color-bg-secondary); + border-radius: var(--radius-md); + border: 1px solid var(--color-border); + transition: all var(--transition-fast); +} + +.binding-detail-item:hover { + border-color: var(--color-border-hover); + box-shadow: var(--shadow-sm); +} + +.detail-task, +.detail-candidate { + display: flex; + flex-direction: column; + gap: var(--space-1); + flex: 1; + min-width: 0; +} + +.detail-label { + font-size: 0.6875rem; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--color-text-tertiary); + font-weight: 600; +} + +.detail-value { + color: var(--color-text-primary); + font-weight: 500; + font-size: 0.875rem; + overflow: hidden; + text-overflow: ellipsis; +} + +.detail-arrow { + color: var(--color-accent); + font-size: 1.25rem; + flex-shrink: 0; +} + +.candidate-attributes { + display: flex; + flex-wrap: wrap; + gap: var(--space-1); + margin-top: var(--space-2); +} + +.attribute { + display: inline-block; + padding: var(--space-1) var(--space-2); + background: var(--color-bg-tertiary); + border-radius: var(--radius-sm); + font-size: 0.6875rem; + color: var(--color-text-secondary); + font-family: var(--font-mono); +} + +@media (max-width: 480px) { + .card-content { + min-width: 0; + } + + .card-value { + font-size: 1.125rem; + word-break: break-all; + } + + .binding-detail-grid { + grid-template-columns: 1fr; + } + + .explorer-header { + flex-direction: column; + align-items: stretch; + } + + .search-box { + max-width: none; + } + + .pagination { + flex-direction: column; + gap: var(--space-3); + } + + .pagination-info { + order: 2; + } + + .pagination-controls { + order: 1; + } + + .bindings-table { + font-size: 0.75rem; + } + + .bindings-table th, + .bindings-table td { + padding: var(--space-2); + } +} diff --git a/frontend/src/components/BindingSpaceExplorer/BindingSpaceExplorer.tsx b/frontend/src/components/BindingSpaceExplorer/BindingSpaceExplorer.tsx new file mode 100644 index 0000000..7e851ed --- /dev/null +++ b/frontend/src/components/BindingSpaceExplorer/BindingSpaceExplorer.tsx @@ -0,0 +1,472 @@ +import { useState, useEffect, useMemo } from 'react'; +import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell } from 'recharts'; +import { Search, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Loader2 } from 'lucide-react'; +import { apiClient, type BindingSpaceRequest, type BindingSpacePage } from '../../api/client'; +import './BindingSpaceExplorer.css'; + +interface Task { + id: string; + name?: string; +} + +interface Candidate { + id: string; + task?: string; + task_id?: string; + [key: string]: any; +} + +interface BindingSpaceExplorerProps { + engineId: string; + instance: any; + tasks: Task[]; + candidates: Candidate[]; + width?: number; + height?: number; +} + +const PAGE_SIZE = 20; + +// Get computed CSS color values +const getCSSColor = (varName: string): string => { + if (typeof window === 'undefined') return '#6b7280'; + return getComputedStyle(document.documentElement).getPropertyValue(varName).trim() || '#6b7280'; +}; + +const getCandidateTaskId = (candidate: Candidate): string | undefined => { + return candidate.task ?? candidate.task_id; +}; + +export const BindingSpaceExplorer: React.FC = ({ + engineId, + instance, + tasks, + candidates, + width, + height = 400, +}) => { + const [bindingData, setBindingData] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [currentPage, setCurrentPage] = useState(0); + const [searchTerm, setSearchTerm] = useState(''); + const [selectedBinding, setSelectedBinding] = useState | null>(null); + // Calculate cardinality per task + const taskCardinality = useMemo(() => { + const cardinalityMap = new Map(); + + tasks.forEach((task) => { + const count = candidates.filter((c) => getCandidateTaskId(c) === task.id).length; + cardinalityMap.set(task.id, count); + }); + + return Array.from(cardinalityMap.entries()).map(([taskId, count]) => { + const task = tasks.find((t) => t.id === taskId); + return { + taskId, + taskName: task?.name || taskId, + count, + }; + }); + }, [tasks, candidates]); + + // Calculate total binding space + const totalBindingSpace = useMemo(() => { + if (taskCardinality.length === 0) return 0; + return taskCardinality.reduce((acc, item) => acc * (item.count || 1), 1); + }, [taskCardinality]); + + // Calculate log10 of binding space for better visualization + const log10BindingSpace = useMemo(() => { + if (totalBindingSpace <= 0) return 0; + return Math.log10(totalBindingSpace); + }, [totalBindingSpace]); + + // Determine complexity level based on log10 scale + const complexityLevel = useMemo(() => { + if (log10BindingSpace < 2) return 'Low'; // < 100 + if (log10BindingSpace < 4) return 'Medium'; // < 10,000 + if (log10BindingSpace < 6) return 'High'; // < 1,000,000 + return 'Very High'; // >= 1,000,000 + }, [log10BindingSpace]); + + const getComplexityColor = () => { + switch (complexityLevel) { + case 'Low': + return '#22c55e'; // green + case 'Medium': + return '#f59e0b'; // amber + case 'High': + return '#ef4444'; // red + case 'Very High': + return '#dc2626'; // dark red + default: + return '#71717a'; // gray + } + }; + + const getBarColor = (count: number) => { + if (taskCardinality.length === 0) return '#8b5cf6'; + const max = Math.max(...taskCardinality.map((t) => t.count)); + const ratio = max > 0 ? count / max : 0; + if (ratio < 0.3) return '#3b82f6'; // blue + if (ratio < 0.7) return '#8b5cf6'; // violet + return '#ec4899'; // pink + }; + + // Fetch bindings from API + const fetchBindings = async (offset: number) => { + setLoading(true); + setError(null); + try { + const request: BindingSpaceRequest = { + engine_id: engineId, + instance, + offset, + limit: PAGE_SIZE, + }; + const data = await apiClient.exploreBindingSpace(request); + setBindingData(data); + } catch (err: any) { + setError(err.message || 'Failed to fetch bindings'); + } finally { + setLoading(false); + } + }; + + // Load initial bindings and reset state when instance/tasks/candidates change + useEffect(() => { + setCurrentPage(0); + setSearchTerm(''); + setSelectedBinding(null); + fetchBindings(0); + }, [engineId, instance, tasks.length, candidates.length]); + + // Handle page change + const handlePageChange = (newPage: number) => { + setCurrentPage(newPage); + fetchBindings(newPage * PAGE_SIZE); + }; + + // Filter bindings based on search term + const filteredBindings = useMemo(() => { + if (!bindingData || !searchTerm) return bindingData?.bindings || []; + + return bindingData.bindings.filter((binding) => { + const searchLower = searchTerm.toLowerCase(); + return Object.entries(binding).some(([task, candidate]) => + task.toLowerCase().includes(searchLower) || + candidate.toLowerCase().includes(searchLower) + ); + }); + }, [bindingData, searchTerm]); + + const totalPages = bindingData + ? Math.ceil(parseInt(bindingData.total_combinations) / PAGE_SIZE) + : 0; + + const CustomTooltip = ({ active, payload }: any) => { + if (active && payload && payload.length) { + const data = payload[0].payload; + return ( +
+

{data.taskName}

+

Candidates: {data.count}

+
+ ); + } + return null; + }; + + return ( +
+
+
+
đź“‹
+
+ Total Tasks + {tasks.length} +
+
+ +
+
🎯
+
+ Total Candidates + {candidates.length} +
+
+ +
+
🔢
+
+ Binding Space + + {totalBindingSpace < 1e6 + ? totalBindingSpace.toLocaleString() + : totalBindingSpace.toExponential(2)} + +
+
+ +
+
⚡
+
+ Complexity + + {complexityLevel} + +
+
+
+ +
+

Candidates per Task

+ + + + + + } cursor={{ fill: getCSSColor('--color-bg-tertiary') }} /> + + {taskCardinality.map((entry, index) => ( + + ))} + + + +
+ + {/* Bindings Explorer Section */} +
+
+

Explore Binding Configurations

+
+ + setSearchTerm(e.target.value)} + className="search-input" + /> +
+
+ + {error && ( +
+ ⚠️ {error} +
+ )} + + {loading ? ( +
+ +

Loading bindings...

+
+ ) : ( + <> +
+ + + + + {tasks.map((task) => ( + + ))} + + + + + {filteredBindings.length === 0 ? ( + + + + ) : ( + filteredBindings.map((binding, index) => { + const globalIndex = currentPage * PAGE_SIZE + index + 1; + const isSelected = selectedBinding === binding; + + return ( + setSelectedBinding(binding)} + > + + {tasks.map((task) => ( + + ))} + + + ); + }) + )} + +
# + {task.name || task.id} + Actions
+ {searchTerm ? 'No bindings match your search' : 'No bindings available'} +
{globalIndex} + + {binding[task.id] || 'N/A'} + + + +
+
+ + {/* Pagination */} + {bindingData && totalPages > 1 && ( +
+
+ Showing {currentPage * PAGE_SIZE + 1} - {Math.min((currentPage + 1) * PAGE_SIZE, parseInt(bindingData.total_combinations))} of {bindingData.total_combinations} +
+
+ + + + Page {currentPage + 1} of {totalPages} + + + +
+
+ )} + + )} +
+ + {/* Selected Binding Detail */} + {selectedBinding && ( +
+

Selected Binding Configuration

+
+ {Object.entries(selectedBinding).map(([taskId, candidateId]) => { + const task = tasks.find((t) => t.id === taskId); + const candidate = candidates.find((c) => c.id === candidateId && getCandidateTaskId(c) === taskId); + + return ( +
+
+ Task: + {task?.name || taskId} +
+
→
+
+ Candidate: + {candidateId} + {candidate && Object.keys(candidate).length > 2 && ( +
+ {Object.entries(candidate) + .filter(([key]) => key !== 'id' && key !== 'task' && key !== 'task_id') + .slice(0, 3) + .map(([key, value]) => ( + + {key}: {typeof value === 'number' ? value.toFixed(2) : String(value)} + + ))} +
+ )} +
+
+ ); + })} +
+
+ )} + +
+

Analysis Insights

+
+
+ Avg Candidates/Task: + + {tasks.length > 0 ? (candidates.length / tasks.length).toFixed(2) : '0.00'} + +
+
+ Min Candidates: + + {taskCardinality.length > 0 && taskCardinality.map((t) => t.count).length > 0 + ? Math.min(...taskCardinality.map((t) => t.count)) + : 0} + +
+
+ Max Candidates: + + {taskCardinality.length > 0 && taskCardinality.map((t) => t.count).length > 0 + ? Math.max(...taskCardinality.map((t) => t.count)) + : 0} + +
+
+ Log10 Space Size: + + {totalBindingSpace > 0 ? log10BindingSpace.toFixed(2) : '0.00'} + +
+
+
+
+ ); +}; diff --git a/frontend/src/components/CodeEditor/CodeEditor.css b/frontend/src/components/CodeEditor/CodeEditor.css index 49a2dbc..e4a1aa2 100644 --- a/frontend/src/components/CodeEditor/CodeEditor.css +++ b/frontend/src/components/CodeEditor/CodeEditor.css @@ -22,3 +22,7 @@ .code-editor-wrapper .cm-line { padding: 0 var(--space-2); } + +.code-editor-wrapper .cm-scroller { + overflow: auto !important; +} diff --git a/frontend/src/components/CodeEditor/CodeEditor.tsx b/frontend/src/components/CodeEditor/CodeEditor.tsx index e0f3dc2..28e1d62 100644 --- a/frontend/src/components/CodeEditor/CodeEditor.tsx +++ b/frontend/src/components/CodeEditor/CodeEditor.tsx @@ -49,7 +49,7 @@ export function CodeEditor({ fontSize: '14px', border: '1px solid var(--color-border)', borderRadius: 'var(--radius-md)', - overflow: 'hidden', + overflow: 'auto', }} /> diff --git a/frontend/src/index.css b/frontend/src/index.css deleted file mode 100644 index 40342f5..0000000 --- a/frontend/src/index.css +++ /dev/null @@ -1,224 +0,0 @@ -:root { - /* Light Theme (Default) */ - --bg-color: #ffffff; - --panel-bg: #f4f4f5; - --text-primary: #18181b; - --text-secondary: #71717a; - --accent: #7c3aed; - --accent-hover: #6d28d9; - --border: #e4e4e7; - --font-family: 'Inter', system-ui, -apple-system, sans-serif; - --status-success-bg: #dcfce7; - --status-success-text: #166534; - --status-error-bg: #fee2e2; - --status-error-text: #991b1b; - --input-bg: #ffffff; -} - -[data-theme="dark"] { - --bg-color: #0f0f11; - --panel-bg: #18181b; - --text-primary: #e4e4e7; - --text-secondary: #a1a1aa; - --accent: #7c3aed; - --accent-hover: #6d28d9; - --border: #27272a; - --status-success-bg: #052e16; - --status-success-text: #4ade80; - --status-error-bg: #450a0a; - --status-error-text: #f87171; - --input-bg: #09090b; -} - -body { - margin: 0; - background-color: var(--bg-color); - color: var(--text-primary); - font-family: var(--font-family); - -webkit-font-smoothing: antialiased; - transition: background-color 0.3s, color 0.3s; -} - -#root { - display: flex; - flex-direction: column; - height: 100vh; -} - -.header { - height: 60px; - border-bottom: 1px solid var(--border); - display: flex; - align-items: center; - padding: 0 24px; - background: var(--panel-bg); - justify-content: space-between; - transition: background-color 0.3s, border-color 0.3s; -} - -.logo-container { - display: flex; - align-items: center; - gap: 12px; -} - -.logo-img { - height: 32px; - width: 32px; - object-fit: contain; - border-radius: 6px; -} - -.logo { - font-weight: 700; - font-size: 1.25rem; - letter-spacing: -0.025em; - background: linear-gradient(to right, #7c3aed, #a1a1aa); - /* Adjusted specific colors or keep generic */ - background: linear-gradient(to right, var(--text-primary), var(--text-secondary)); - -webkit-background-clip: text; - background-clip: text; - -webkit-text-fill-color: transparent; - color: transparent; - /* Fallback */ -} - -/* Override logo gradient for dark/light contrast if needed, simplified to text color for reliability */ -.logo { - background: none; - -webkit-text-fill-color: initial; - color: var(--text-primary); -} - -.main { - flex: 1; - display: flex; - overflow: hidden; -} - -.editor-pane, -.result-pane { - flex: 1; - display: flex; - flex-direction: column; - border-right: 1px solid var(--border); - min-width: 0; - transition: border-color 0.3s; -} - -.result-pane { - border-right: none; - background: var(--input-bg); - transition: background-color 0.3s; -} - -.pane-header { - padding: 12px 16px; - font-size: 0.875rem; - font-weight: 600; - color: var(--text-secondary); - border-bottom: 1px solid var(--border); - text-transform: uppercase; - letter-spacing: 0.05em; - background: var(--panel-bg); -} - -.toolbar { - height: 56px; - border-bottom: 1px solid var(--border); - display: flex; - align-items: center; - padding: 0 16px; - gap: 12px; - background: var(--bg-color); - transition: background-color 0.3s, border-color 0.3s; -} - -.btn { - background: var(--accent); - color: white; - border: none; - padding: 8px 16px; - border-radius: 6px; - font-weight: 500; - cursor: pointer; - transition: background 0.2s; - font-size: 0.875rem; - display: inline-flex; - align-items: center; - justify-content: center; -} - -.btn:hover { - background: var(--accent-hover); -} - -.btn-secondary { - background: var(--panel-bg); - border: 1px solid var(--border); - color: var(--text-primary); -} - -.btn-secondary:hover { - background: var(--border); -} - -.btn:disabled { - opacity: 0.7; - cursor: not-allowed; - filter: grayscale(0.5); -} - -select { - background: var(--panel-bg); - border: 1px solid var(--border); - color: var(--text-primary); - padding: 8px 12px; - border-radius: 6px; - font-size: 0.875rem; - outline: none; - min-width: 200px; -} - -textarea { - flex: 1; - background: var(--input-bg); - color: var(--text-primary); - font-family: 'JetBrains Mono', 'Fira Code', monospace; - font-size: 13px; - border: none; - padding: 16px; - resize: none; - outline: none; - line-height: 1.5; - transition: background-color 0.3s, color 0.3s; -} - -.result-view { - padding: 24px; - overflow-y: auto; - font-family: 'JetBrains Mono', monospace; - font-size: 13px; - white-space: pre-wrap; - color: var(--text-primary); -} - -.status-badge { - padding: 4px 8px; - border-radius: 4px; - font-size: 12px; - font-weight: 600; - text-transform: uppercase; - margin-bottom: 16px; - display: inline-block; -} - -.status-success { - background: var(--status-success-bg); - color: var(--status-success-text); -} - -.status-error { - background: var(--status-error-bg); - color: var(--status-error-text); -} \ No newline at end of file diff --git a/frontend/src/pages/Playground/Playground.css b/frontend/src/pages/Playground/Playground.css index 6e7108d..23043cd 100644 --- a/frontend/src/pages/Playground/Playground.css +++ b/frontend/src/pages/Playground/Playground.css @@ -54,6 +54,7 @@ font-size: 0.875rem; cursor: pointer; min-width: 200px; + max-width: 280px; transition: all var(--transition-fast); } @@ -67,6 +68,18 @@ border-color: var(--color-accent); } +.example-select optgroup { + font-weight: 600; + color: var(--color-text-primary); + font-style: normal; + padding: var(--space-1) 0; +} + +.example-select option { + padding: var(--space-1) var(--space-2); + font-weight: 400; +} + .panel-content { flex: 1; padding: var(--space-4); @@ -280,6 +293,44 @@ } /* Solutions */ +.solution-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--space-3); +} + +.solution-header h4 { + margin: 0; + font-size: 1rem; + font-weight: 600; +} + +.solution-objective { + display: flex; + align-items: center; + gap: var(--space-2); + padding: var(--space-2) var(--space-3); + background-color: var(--color-bg-secondary); + border-radius: var(--radius-md); + border: 1px solid var(--color-border); +} + +.objective-label { + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--color-text-tertiary); +} + +.objective-value { + font-size: 1rem; + font-weight: 700; + color: var(--color-accent); + font-family: var(--font-mono); +} + .binding-table { margin: var(--space-3) 0; overflow-x: auto; @@ -306,6 +357,61 @@ .binding-table td code { font-size: 0.875rem; + font-family: var(--font-mono); + background-color: var(--color-bg-elevated); + padding: var(--space-1) var(--space-2); + border-radius: var(--radius-sm); +} + +.solution-features { + margin-top: var(--space-4); + padding-top: var(--space-4); + border-top: 1px solid var(--color-border); +} + +.features-toggle { + display: flex; + align-items: center; + gap: var(--space-2); + width: 100%; + padding: var(--space-2) 0; + background: none; + border: none; + cursor: pointer; + color: var(--color-text-primary); + font-size: 0.9375rem; + transition: color var(--transition-fast); +} + +.features-toggle:hover { + color: var(--color-accent); +} + +.features-toggle-icon { + font-size: 0.75rem; + color: var(--color-text-tertiary); + transition: transform var(--transition-fast); + display: inline-block; + width: 1rem; +} + +.features-content { + margin-top: var(--space-3); + padding: var(--space-3); + background-color: var(--color-bg-secondary); + border-radius: var(--radius-md); + animation: slideDown 0.2s ease-out; +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-8px); + } + to { + opacity: 1; + transform: translateY(0); + } } .solution-qos { @@ -396,11 +502,19 @@ color: var(--color-text-primary); } +.binding-space-summary { + margin-bottom: var(--space-6); +} + +.binding-space-summary h3 { + margin: 0 0 var(--space-4) 0; +} + .binding-space-metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-4); - margin-bottom: var(--space-6); + margin-bottom: var(--space-4); } .metric-card { diff --git a/frontend/src/pages/Playground/Playground.tsx b/frontend/src/pages/Playground/Playground.tsx index dcad0d0..77c4565 100644 --- a/frontend/src/pages/Playground/Playground.tsx +++ b/frontend/src/pages/Playground/Playground.tsx @@ -9,6 +9,7 @@ import { Alert } from '../../components/ui/Alert'; import { Badge } from '../../components/ui/Badge'; import { Tabs } from '../../components/ui/Tabs'; import { CodeEditor } from '../../components/CodeEditor/CodeEditor'; +import { BindingSpaceExplorer } from '../../components/BindingSpaceExplorer/BindingSpaceExplorer'; import './Playground.css'; const ajv = new Ajv({ allErrors: true }); @@ -28,20 +29,35 @@ const DEFAULT_OPTIONS = `{ "iterations_count": 1000 }`; +const EMPTY_OPTIONS = `{}\n`; + type JobState = 'idle' | 'validating' | 'queued' | 'running' | 'completed' | 'failed'; // Available examples in /examples directory -const AVAILABLE_EXAMPLES = [ - 'common-basic.json', - 'common-huge.json', - 'common-mixed.json', - 'minizinc-constrained-loop.json', - 'minizinc-huge.json', - 'minizinc-tight.json', - 'random-search-example.json', - 'random-search-huge.json', - 'random-search-valid.json' -]; +const AVAILABLE_EXAMPLES = { + 'Demo Examples': [ + 'demo/01_simple_seq.json', + 'demo/02_parallel.json', + 'demo/03_xor_choice.json', + 'demo/04_conflict.json', + 'demo/05_mono_obj_various.json', + 'demo/06_loops.json', + 'demo/07_soft_constraints.json', + 'demo/08_dependencies.json', + 'demo/09_mixed.json', + 'demo/10_large_scale.json', + 'demo/11_multi_obj_negative.json', + 'demo/12_many_obj_pareto.json' + ], + 'Literature Examples': [ + 'literature/benatallah.json', + 'literature/bultan.json', + 'literature/cremaschi.json', + 'literature/netedu.json', + 'literature/pautasso.json', + 'literature/zhang.json' + ] +}; export function Playground() { // State @@ -56,6 +72,7 @@ export function Playground() { const [jobState, setJobState] = useState('idle'); const [result, setResult] = useState(null); const [error, setError] = useState(null); + const [currentInstance, setCurrentInstance] = useState(null); const fileInputRef = useRef(null); const validateRef = useRef(null); @@ -73,6 +90,26 @@ export function Playground() { } }, [selectedEngine]); + useEffect(() => { + if (!selectedEngine) return; + + // Keep the options editor in sync with the selected engine. + // If the engine has no options defaults, show an empty object. + const loadDefaultOptions = async () => { + try { + const defaults = await apiClient.getEngineDefaultOptions(selectedEngine); + const normalized = (defaults && typeof defaults === 'object' && !Array.isArray(defaults)) ? defaults : {}; + const keys = Object.keys(normalized); + setSolverOptions(keys.length > 0 ? `${JSON.stringify(normalized, null, 2)}\n` : EMPTY_OPTIONS); + } catch (err) { + console.warn(`Failed to load default options for engine '${selectedEngine}', using empty options`, err); + setSolverOptions(EMPTY_OPTIONS); + } + }; + + loadDefaultOptions(); + }, [selectedEngine]); + const loadEngines = async () => { try { const data = await apiClient.getEngines(); @@ -141,7 +178,10 @@ export function Playground() { try { // In production, examples should be served via the gateway or a static path - const response = await fetch(`/examples/${exampleFile}`); + const cacheBuster = Date.now(); + const response = await fetch(`/examples/${exampleFile}?v=${cacheBuster}`, { + cache: 'no-store', + }); if (!response.ok) { throw new Error(`Failed to load example: ${response.statusText}`); } @@ -162,6 +202,7 @@ export function Playground() { try { const instance = JSON.parse(inputJson); + setCurrentInstance(instance); const options = sendOptions ? JSON.parse(solverOptions) : {}; const response = await apiClient.analyze({ @@ -179,6 +220,38 @@ export function Playground() { } }; + /** + * Inspects a solve result for anomalies: empty solutions, empty bindings, etc. + * Sets user-facing warnings/errors so issues are visible in the UI. + */ + const checkAndWarnEmptyResult = (solveResult: any) => { + if (!solveResult) return; + + const solutions = solveResult.solutions; + + // No solutions at all + if (!solutions || solutions.length === 0) { + setError( + 'The solver returned no solutions. The instance may be infeasible under the current constraints, ' + + 'or the engine did not find any feasible binding within the given budget.' + ); + return; + } + + // Check for solutions with empty or missing bindings + const emptyBindingSolutions = solutions.filter( + (s: any) => !s.binding || Object.keys(s.binding).length === 0 + ); + + if (emptyBindingSolutions.length > 0) { + setError( + `${emptyBindingSolutions.length} solution(s) have an empty binding — this likely indicates ` + + 'an engine bug or an unsupported instance structure. Please report this instance to the administrator ' + + 'so it can be investigated.' + ); + } + }; + const handleSolve = async () => { setJobState('validating'); setError(null); @@ -186,6 +259,7 @@ export function Playground() { try { const instance = JSON.parse(inputJson); + setCurrentInstance(instance); // Client-side validation if (validateRef.current) { @@ -221,13 +295,25 @@ export function Playground() { return; } + // Handle synchronous failure (engine returned error directly) if (jobResponse.status === 'failed') { - setResult(jobResponse.result || { error: jobResponse.error }); + setResult(jobResponse.result || { error: jobResponse.error || 'The solver could not process this instance.' }); setJobState('failed'); return; } - // Poll for job completion + // Handle synchronous completion (engine returned solution directly, no polling needed) + if (jobResponse.status === 'completed') { + const syncResult = jobResponse.result; + if (syncResult) { + checkAndWarnEmptyResult(syncResult); + } + setResult(syncResult || { solutions: [], _warning: 'The engine returned an empty response.' }); + setJobState('completed'); + return; + } + + // Asynchronous job: poll for completion setJobState('running'); const finalResult = await apiClient.pollJob( jobResponse.job_id, @@ -238,10 +324,27 @@ export function Playground() { } ); - setResult(finalResult); + if (finalResult) { + checkAndWarnEmptyResult(finalResult); + } + setResult(finalResult || { solutions: [], _warning: 'The engine returned an empty response.' }); setJobState('completed'); } catch (err: any) { - setError(err.message || 'Solve failed'); + const message = err.message || 'Solve failed'; + // Provide user-friendly messages for common errors + if (message.includes('HTTP 404')) { + setError('The solver job could not be found. The engine may have completed synchronously or restarted. Please try again.'); + } else if (message.includes('timed out') || message.includes('Polling timed out')) { + setError('The solver is taking longer than expected. The instance may be very large or the engine may be overloaded. Try reducing the problem size or iterations count.'); + } else if (message.includes('HTTP 502') || message.includes('HTTP 503') || message.includes('HTTP 504')) { + setError('The solver engine is temporarily unavailable. Please check that the engine is running and try again.'); + } else if (message.includes('Failed to fetch') || message.includes('NetworkError')) { + setError('Could not connect to the API gateway. Please check your network connection and ensure the server is running.'); + } else if (message.includes('JSON')) { + setError('Invalid JSON in the instance or options editor. Please check the syntax and try again.'); + } else { + setError(message); + } setJobState('failed'); } }; @@ -262,8 +365,24 @@ export function Playground() { className="example-select" > - {AVAILABLE_EXAMPLES.map(ex => ( - + {Object.entries(AVAILABLE_EXAMPLES).map(([category, examples]) => ( + + {examples.map(ex => { + const fileName = ex.split('/')[1].replace('.json', ''); + // Format: "01_simple_seq" -> "01 - Simple Seq" + const displayName = fileName + .replace(/_/g, ' ') + .split(' ') + .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' ') + .replace(/^(\d+) /, '$1 - '); + return ( + + ); + })} + ))} - {/* Solver Options */} + {/* Engine Options */}
- +