Skip to content

What is MDEO Cloud?

MDEO Cloud is a web-based platform for model-driven engineering optimisation: you describe a design space as a metamodel, a starting model and a set of model transformations, state what makes one design better than another, and let a search algorithm explore the space for you.

It is a fork of MDEOptimiser that replaces the Eclipse-based tooling with a browser workbench and a distributed execution platform.

The problem it solves

Many engineering problems are really search problems over structured artefacts:

  • Which components should each class of a system own, so that cohesion is high and coupling is low?
  • How should tasks be spread across a team without overloading anyone?
  • Which set of features fits into the next release, given a budget and a dependency graph?

All of these have the same shape. There is a structure (a model), a set of legal edits to that structure, and one or more numeric criteria that say how good a structure is. MDEO Cloud lets you write down exactly those three things and hands the rest — mutation, evaluation, multi-objective search, parallel execution — to the platform.

What you write

A complete optimisation problem is five kinds of file, each with its own language, editor and validation:

FileLanguagePurpose
.mmMetamodelThe structure of your domain: classes, properties, associations
.mModelA concrete instance to start the search from
.mtModel TransformationThe legal edits — the moves the search may make
.fnScriptObjectives and constraints, as ordinary functions over the model
.configConfigWhich files to use, what to optimise, and how to search

Here is what that looks like end to end. First the domain:

mm
// Domain of the task allocation problem: a project owns tasks and developers,
// and every task may be assigned to at most one developer.

enum Priority {
    LOW
    MEDIUM
    HIGH
}

class Project {
    name: string
}

abstract class WorkItem {
    name: string
    effort: int
}

class Task extends WorkItem {
    priority: Priority
}

class Developer {
    name: string
    capacity: int
}

Project.tasks[*] *--> Task.project
Project.developers[*] *--> Developer.project
Task.assignee[0..1] <--> Developer.tasks[*]

A starting point:

mdeo-model
using "./tasks.mm"

apollo : Project {
    name = "Apollo"
}

login : Task {
    name = "Login screen"
    effort = 5
    priority = Priority.HIGH
}

reporting : Task {
    name = "Reporting dashboard"
    effort = 8
    priority = Priority.MEDIUM
}

migration : Task {
    name = "Database migration"
    effort = 13
    priority = Priority.LOW
}

alice : Developer {
    name = "Alice"
    capacity = 10
}

bob : Developer {
    name = "Bob"
    capacity = 15
}

apollo.tasks -- login
apollo.tasks -- reporting
apollo.tasks -- migration
apollo.developers -- alice
apollo.developers -- bob

The moves the search is allowed to make:

mt
using "./tasks.mm"

// Give an unassigned task to some developer.
match {
    task: Task {
        effort > 0
    }
    developer: Developer { }
    create task.assignee -- developer
}

What "better" means:

fn
using "./tasks.mm"

// Total effort of every task that nobody has picked up yet.
fun unassignedEffort(): int {
    var total = 0
    for (task in Task.all()) {
        if (task.assignee == null) {
            total = total + task.effort
        }
    }
    return total
}

// How much the busiest developer is overloaded beyond their capacity.
fun maxOverload(): int {
    var worst = 0
    for (developer in Developer.all()) {
        var assigned = 0
        for (task in developer.tasks) {
            assigned = assigned + task.effort
        }
        var overload = assigned - developer.capacity
        if (overload > worst) {
            worst = overload
        }
    }
    return worst
}

// Constraint: every high priority task has to be assigned.
// 0 means satisfied, any larger value is the magnitude of the violation.
fun unassignedHighPriority(): int {
    var violations = 0
    for (task in Task.all()) {
        if (task.priority == Priority.HIGH && task.assignee == null) {
            violations = violations + 1
        }
    }
    return violations
}

And finally, how to run it:

mdeo-config
problem {
    metamodel = "./tasks.mm"
    model = "./plan.m"
}

goal {
    import { unassignedEffort, maxOverload, unassignedHighPriority } from "./objectives.fn"

    minimize unassignedEffort
    minimize maxOverload
    constraint unassignedHighPriority
}

search {
    mutations {
        using "./assign.mt"
        using "./unassign.mt"
    }
}

solver {
    algorithm = NSGAII

    parameters {
        population = 40
        variation = mutation

        mutation {
            step = 1
            strategy = random
        }
    }

    termination {
        evolutions = 500
    }
}

runtime {
    timeout {
        script = 1000
        transformation = 1000
    }

    resources {
        threads = 4
    }
}

The walkthrough builds this example up step by step and runs it.

What makes it different

Everything runs in the browser. Metamodels and models have graphical editors as well as textual ones, and both views edit the same file. Language support — completion, validation, formatting, go-to-definition — comes from Langium language servers that run in a web worker, so editing stays responsive without a round trip to a server.

Search runs somewhere else. An optimisation run is dispatched to dedicated execution nodes. A single run can be spread across several nodes and many threads, and the workbench streams progress back over a WebSocket while you keep working.

Every language is a plugin. The five languages above are not built into the workbench. Each one is served by a plugin — an HTTP service that publishes a manifest describing the languages, editors and language extensions it provides. The workbench discovers plugins at runtime and loads their code as ES modules. Adding a sixth language means writing a plugin, not patching the workbench.

That last point is the reason this platform exists as a platform: see the plugin catalogue for what ships with it, and the developer guide for how to add your own.

Where to go next

Released under the terms of the repository licence.