FoundryProductsTechnologyCompanyInvestor relationsResource libraryNews
Contact us
Resource library
    Resource library home
    Developer resources
      Entropy quantum optimization
        Dirac Quick Start
        Dirac-3 Developer Beginner Guide
        Multibody formulation
        QUBO formulation
        QLCBO formulation
        QBoost formulation
        qci-client software package
        eqc-direct software package
        eqc-models software package
          Getting Started
          Basic Usage
          eqc_models
          Dependencies
      Quantum random number generation
      Reservoir computing
    Applications
    Lessons
    Research and publications
    Support

Couldn’t find what you are looking for? Reach out to technical support.

Contact support
Privacy PolicyCookie PolicyTerms of UseForward Looking StatementsAccessibility Statement
Terms and Conditions of SaleEnd User License Agreement

© 2018-2026 Quantum Computing Inc.

Download

Default

Source code for eqc_models.assignment.resource

  • from typing import (Dict, List)
  • import numpy as np
  • from eqc_models.base.quadratic import ConstrainedQuadraticModel
  • from eqc_models.base.constraints import InequalitiesMixin
  • [docs]
  • class ResourceAssignmentModel(InequalitiesMixin, ConstrainedQuadraticModel):
  • """
  • Resource assignment model
  • Parameters
  • ------------
  • resources : List
  • tasks : List
  • >>> # name is not a required attribute of the resources or tasks
  • >>> crews = [{"name": "Maintenance Crew 1", "skills": ["A", "F"], "capacity": 5, "cost": 4},
  • ... {"name": "Baggage Crew 1", "skills": ["B"], "capacity": 4, "cost": 1},
  • ... {"name": "Maintenance Crew 2", "skills": ["A", "F"], "capacity": 5, "cost": 2}]
  • >>> tasks = [{"name": "Refuel", "skill_need": "F", "load": 3},
  • ... {"name": "Baggage", "skill_need": "B", "load": 1}]
  • >>> model = ResourceAssignmentModel(crews, tasks)
  • >>> assignments = model.createAssignmentVars()
  • >>> assignments
  • [{'resource': 0, 'task': 0}, {'resource': 1, 'task': 1}, {'resource': 2, 'task': 0}]
  • >>> A, b, senses = model.constrainAssignments(assignments)
  • >>> A
  • array([[3., 0., 0.],
  • [0., 1., 0.],
  • [0., 0., 3.],
  • [3., 0., 3.],
  • [0., 3., 0.]], dtype=float32)
  • >>> b
  • array([5., 4., 5., 3., 3.], dtype=float32)
  • >>> senses
  • ['LE', 'LE', 'LE', 'EQ', 'EQ']
  • >>> A, b = model.constraints
  • >>> A
  • array([[3., 0., 0., 1., 0., 0.],
  • [0., 1., 0., 0., 1., 0.],
  • [0., 0., 3., 0., 0., 1.],
  • [3., 0., 3., 0., 0., 0.],
  • [0., 3., 0., 0., 0., 0.]])
  • """
  • def __init__(self, resources, tasks):
  • self.resources = resources
  • self.checkTasks(tasks)
  • self.tasks = tasks
  • self.assignments = assignments = self.createAssignmentVars()
  • n = len(assignments) + len(resources)
  • self.variables = [f"a{i}" for i in range(len(assignments))]
  • self.upper_bound = np.ones((n,))
  • self.upper_bound[-len(resources):] = [resource["capacity"] for resource in resources]
  • A, b, senses = self.constrainAssignments(assignments)
  • J = np.zeros((n, n))
  • C = np.zeros((n,), dtype=np.float32)
  • # objective is to minimize cost of assignments
  • for j, assignment in enumerate(assignments):
  • C[j] = resources[assignment["resource"]]["cost"] * tasks[assignment["task"]]["load"]
  • super(ResourceAssignmentModel, self).__init__(C, J, A, b)
  • self.senses = senses
  • # always use a machine slack
  • self.machine_slacks = 1
  • [docs]
  • @classmethod
  • def checkTasks(cls, tasks):
  • for task in tasks:
  • if "skill_need" not in task:
  • raise ValueError("All tasks must have the skill_need attribute")
  • if "load" not in task:
  • raise ValueError("All tasks must have the load attribute")
  • [docs]
  • def createAssignmentVars(self):
  • """ Examine all combinatins of possible crew-task assignments """
  • assign_vars = []
  • resources = self.resources
  • tasks = self.tasks
  • for i, resource in enumerate(resources):
  • skills = resource["skills"]
  • for j, task in enumerate(tasks):
  • if task["skill_need"] in skills:
  • assign_vars.append({"resource": i, "task": j})
  • return assign_vars
  • [docs]
  • def constrainAssignments(self, assignments : List) -> List:
  • """
  • Examine the assignments to determine the necessary constraints to
  • ensure feasibility of solution.
  • """
  • # A is sized using the number of crews and the number of assignment variables plus slacks
  • m1 = len(self.resources)
  • m2 = len(self.tasks)
  • n1 = len(assignments)
  • m = m1 + m2
  • n = n1
  • A = np.zeros((m, n), dtype=np.float32)
  • b = np.zeros((m,), dtype=np.float32)
  • for i, resource in enumerate(self.resources):
  • b[i] = resource["capacity"]
  • for k, assignment in enumerate(assignments):
  • if assignment["resource"] == i:
  • A[i, k] = self.tasks[assignment["task"]]["load"]
  • assignment_coeff = np.max(A)
  • for i, task in enumerate(self.tasks):
  • b[m1+i] = assignment_coeff
  • for k, assignment in enumerate(assignments):
  • if assignment["task"] == i:
  • A[m1+i, k] = assignment_coeff
  • senses = ["LE" for resource in self.resources] + ["EQ" for task in self.tasks]
  • return A, b, senses
  • @property
  • def sum_constraint(self) -> int:
  • """ This value is a suggestion which should be used with a machine slack """
  • sc = 0
  • sc += sum([resource["capacity"] for resource in self.resources])
  • sc += len(self.tasks)
  • return sc
  • [docs]
  • def decode(self, solution : np.array) -> List[Dict]:
  • """
  • Convert the binary solution into a list of tasks
  • """
  • # ensure solution is array
  • solution = np.array(solution)
  • resource_assignments = [[] for resource in self.resources]
  • vals = [val for val in set(solution) if val <= 1.0]
  • # check if there are fractional values less than 1
  • if solution[~np.logical_or(solution==0, solution>=1)].size>0:
  • # iterate over the values and assign tasks by largest value for tasks
  • # not assigned already
  • remaining_tasks = list(range(len(self.tasks)))
  • fltr = self.upper_bound==1
  • while len(remaining_tasks) > 0 and solution[fltr].shape[0]>0:
  • largest = np.max(solution[fltr])
  • indices, = np.where(np.logical_and(fltr, solution == largest))
  • for idx in indices:
  • assignment = self.assignments[idx]
  • if assignment["task"] in remaining_tasks:
  • task = self.tasks[assignment["task"]]
  • resource_assignments[assignment["resource"]].append(task)
  • del remaining_tasks[remaining_tasks.index(assignment["task"])]
  • break
  • fltr = np.logical_and(fltr, solution < largest)
  • else:
  • # Use the restriction that a task cannot be assigned more than once
  • for j, task in enumerate(self.tasks):
  • highest = 0
  • best_resource = None
  • for a, assignment in zip(solution, self.assignments):
  • if assignment["task"] == j:
  • if a > highest:
  • highest = a
  • best_resource = assignment["resource"]
  • assert best_resource is not None, f"solution had no positive assignment values for {task}"
  • resource_assignments[best_resource].append(task)
  • return resource_assignments
Next page

Content

  • Source code for eqc_models.assignment.resource