تخطٍّ إلى المحتوى
DispatchAtlas
بحث

عقود المجال

dispatchatlas.core هو حدّ الحزمة الداخلي. يستخدم كائنات غير قابلة للتغيير ومن المكتبة القياسية فقط، حتى تستهلك النسخ المرجعية والحلّالات والتجارب والتحليل والتوثيق مفردات جدولة مشتركة واحدة.

🗂️ نموذج الجدولة

تُمثَّل المسائل بـ ProblemSpec وTaskSpec وResourceSpec وDependency وObjective وConstraint. تستخدم الجداول المرشَّحة Assignment وSchedule وObjectiveValue وScheduleResult.

التحقّق صريح:

from dispatchatlas.core import (
    Duration,
    Objective,
    ObjectiveSense,
    ProblemId,
    ProblemSpec,
    ResourceAmount,
    ResourceId,
    ResourceRequirement,
    ResourceSpec,
    TaskId,
    TaskSpec,
    validate_problem,
)
 
cpu = ResourceId("cpu")
 
problem = ProblemSpec(
    id=ProblemId("smoke"),
    tasks=(
        TaskSpec(
            TaskId("task-a"),
            Duration(1.0),
            demands=(ResourceRequirement(cpu, ResourceAmount(1.0)),),
        ),
    ),
    resources=(ResourceSpec(cpu, ResourceAmount(1.0)),),
    objectives=(Objective("makespan", ObjectiveSense.MINIMIZE),),
)
 
validated = validate_problem(problem)

تُعيد validate_problem كائن ValidatedProblem مع ختم تحقّق وتقرير قابل للقراءة آليًّا. تتحقّق validate_schedule من تغطية المهام، وسعة الموارد، وحدود التوقيت، والتبعيّات.

🔗 التخصيص المشترك متعدّد الموارد

قد تطلب مهمة أكثر من مورد في آنٍ واحد. TaskSpec.demands صفٌّ (tuple) من ResourceRequirement، ويخصّص باني الجدول المهمة بشكل مشترك عبر كل مورد تطلبه، ممسكًا بها معًا طوال مدة المهمة بأكملها. لذا يسجّل الجدول المرشَّح كل تنسيب بوصفه Assignment.resource_ids — صفًّا، لا موردًا واحدًا — وتؤكّد validate_schedule أن مهمّتين متداخلتين زمنيًّا لا تتشاركان موردًا أبدًا.

رسم تعارض الموارد هو رافعة الجدولة: مهمّتان تتقاطع مجموعتا طلبهما يجب أن تتسلسلا، بينما مهمّتان مجموعتاهما منفصلتان تعملان بالتزامن.

from dispatchatlas.core import ResourceAmount, ResourceId, ResourceRequirement
 
# A task that co-allocates a compute node and an accelerator simultaneously.
demands = (
    ResourceRequirement(ResourceId("edge-0"), ResourceAmount(1.0)),
    ResourceRequirement(ResourceId("gpu-1"), ResourceAmount(1.0)),
)

تمارس عائلتا السلسلة المتصلة accelerator-coscheduling، distributed-transaction وfpga-partitioning هذه الرافعة — الأولى بإمساك ثابت للحوسبة-زائد-المسرّع، والثانية بمجموعة أقفال متغيّرة العدّ على شظايا البيانات. يُجدوِل القابل للتنفيذ examples/inspect_coallocation.py كليهما ويُظهر مهام الموارد المنفصلة تعمل بالتوازي بينما تتسلسل المهام التي تتشارك الموارد.

🧩 التنفيذ القابل للتشكيل

قد تعمل مهمة في أيٍّ من عدّة أنماط. TaskSpec.modes صفٌّ من TaskMode — كلٌّ منها زوج (demands, duration)، حيث ينفّذ النمط الأعرض (الذي يطلب موارد أكثر) في زمن أقصر، تسريع القابلية للتشكيل. عندما تُضبط modes تصبح المهمة قابلة للتشكيل: يختار باني الجدول، لكل مهمة، النمط الذي ينتهي أبكر بحسب الموارد المتاحة، فيقرّر ترتيب الجدول قدر التوازي الذي تطالب به كل مهمة. تترك المهمة الصلبة modes غير مضبوطة (الافتراضي)، وتكون duration وdemands العلويّتان نمطها الوحيد، الذي تجدوله الخلفية الدقيقة كمرجع متحفّظ. تؤكّد validate_schedule أن كل تنسيب يطابق نمطًا مُعلَنًا واحدًا، والتنفيذ القابل للتشكيل والتنفيذ غير الدقيق (mandatory_duration) متنافيان — تختار المهمة توازيها أو تُسقط العمل الاختياري، لا كليهما.

from dispatchatlas.core import (
    Duration,
    ResourceAmount,
    ResourceId,
    ResourceRequirement,
    TaskMode,
)
 
# Two ways to run one job: wide-and-fast on two workers, or narrow-and-slow on one.
modes = (
    TaskMode(
        demands=(
            ResourceRequirement(ResourceId("worker-0"), ResourceAmount(1.0)),
            ResourceRequirement(ResourceId("worker-1"), ResourceAmount(1.0)),
        ),
        duration=Duration(1.0),
    ),
    TaskMode(
        demands=(ResourceRequirement(ResourceId("worker-0"), ResourceAmount(1.0)),),
        duration=Duration(1.8),
    ),
)

تمارس عائلة السلسلة المتصلة elastic-serverless-autoscale هذه الرافعة: قد يتوسّع كل استدعاء دالة إلى عامل واحد أو اثنين أو أربعة مسحوبين من مجمّع اندفاع مشترك صغير، فيقرّر ترتيب الجدول أيّ الاستدعاءات تطالب بالأنماط العريضة-السريعة الشحيحة وأيّها يعمل ضيّقًا — مقايضة بين زمن الاستجابة وكلفة الموارد.

🛰️ الجدولة المشتركة للعصبة (gang)

المهام التي تتشارك TaskSpec.gang_id تشكّل عصبة يجب أن يبدأ عمّالها جميعًا في الوقت نفسه على موارد متمايزة — بدء مشترك بمبدأ الكل-أو-لا-شيء، كما تحتاج مهمة تدريب-موزّع أو MPI متزامنة إلى عمّالها يعملون معًا. يضع الباني التسلسلي عصبة كاملة بشكل ذرّي عند أبكر لحظة تكون فيها موارد كل عامل متاحة، حتى عندما كان بإمكان عامل أن يبدأ أبكر منفردًا؛ ترفض validate_schedule عصبةً لا يبدأ عمّالها معًا (schedule.feasibility.gang_cosched). عامل العصبة صلب (غير قابل للتشكيل)، لأن العصبة تبدأ معًا بعرض ثابت؛ تترك المهمة المستقلة gang_id غير مضبوطة.

from dispatchatlas.core import (
    Duration,
    ResourceAmount,
    ResourceId,
    ResourceRequirement,
    TaskId,
    TaskSpec,
)
 
# Two workers of one training job that must launch together on distinct accelerators.
gang = "train-job-0"
workers = tuple(
    TaskSpec(
        id=TaskId(f"worker-{index}"),
        duration=Duration(2.0),
        demands=(ResourceRequirement(ResourceId(f"acc-{index}"), ResourceAmount(1.0)),),
        gang_id=gang,
    )
    for index in range(2)
)

تمارس عائلة السلسلة المتصلة distributed-training-gang هذه الرافعة: عصب من عاملين إلى أربعة عمّال تعيد استخدام مجمّع مسرّعات مشترك وتصل المهام عبر الزمن، فلا يمكن لمهمة أن تبدأ حتى تتحرّر مسرّعات كافية في آنٍ واحد، ويقرّر ترتيب الجدول أيّ مهمة تكتسب مجموعة عمّالها الكاملة أولًا.

⚖️ الحصّة العادلة متعدّدة المستأجرين

تحمل المهام TaskSpec.tenant_id اختياريًّا يَسِم المستأجر المالك لأجل محاسبة الحصّة العادلة متعدّدة المستأجرين. يسجّل هدف dominant-resource-share (ObjectiveKind.DOMINANT_RESOURCE_SHARE، وفق عدالة المورد المهيمن لـ Ghodsi وآخرين) مدى توازن الحصص المهيمنة للمستأجرين: الحصّة المهيمنة لكل مستأجر هي أكبر كسر، عبر الموارد، من السعة-الزمن الكلّية لمورد تشغله مهامه، والهدف هو التشتّت بين المستأجر الأكثر والأقلّ خدمةً — 0.0 لجدول متساوي-الحصّة-المهيمنة (عادل)، وأعلى حين يحتكر مستأجرٌ موردَه المهيمن. الهدف بمعنى التصغير ويُعيد DEFERRED على نسخة بلا مستأجرين. tenant_id متعامد مع التنفيذ بالعصبة والقابل للتشكيل وغير الدقيق — قد تكون مهام مستأجرٍ أيًّا منها؛ تترك المهمة بلا مستأجر tenant_id غير مضبوطة.

الرافعة هي التنسيب، لا ترتيب الجدول: إجمالي إشغال موارد مستأجرٍ مثبَّت بحمله، فعلى أيّ موارد تَحُطّ مهامه هو ما يوازن الحصص المهيمنة أو يحرفها. يسجّل القابل للتنفيذ examples/multi_tenant_fairshare_study.py تنسيبًا عادلًا (مشتّتًا) مقابل تنسيب محتكِر لمستأجر ثقيل وآخر خفيف على مجمّع من ثلاث عقد، مُظهرًا الرافعة صراحةً.

⏱️ المواعيد النهائية الصارمة والمرنة

قد تحمل مهمة موعدًا نهائيًّا للإنجاز TaskSpec.deadline، ويصنّف TaskSpec.deadline_kind كيف يُحكَم على التجاوز. الافتراضي ConstraintKind.HARD يجعل الموعد المتجاوَز انتهاكَ جدوى: تطلق validate_schedule مشكلة حاجبة schedule.feasibility.deadline ويُبلَّغ عن الجدول بأنه غير مجدٍ. ConstraintKind.SOFT يجعل التجاوز نفسه مجرّد غرامة تأخّر — يظلّ الجدول مجديًا بينما يتراكم الفائض إلى هدف lateness (ObjectiveKind.LATENESS)، فتُعاقَب مهمة الزمن-الحقيقي-المرن على التأخّر دون جعل الجدول غير مجدٍ. لا أثر لهذا النوع حين تكون deadline غير مضبوطة.

القراءتان للموعد النهائي مستقلّتان: يقيّد الموعد الصارم المنطقةَ المجدية بينما يشكّل الموعد المرن سطح الهدف، وقد تستخدم مهمة أيًّا منهما. يمرّ القابل للتنفيذ examples/infeasibility_study.py بحالة الموعد الصارم من البداية إلى النهاية — نسخة مفرطة-التقييد يُبلَّغ عنها بأنها غير مجدية، والترتيب الأقلّ-عدم-جدوى حين لا يوجد جدول مجدٍ.

💰 نماذج الكلفة

تُوصَف الجدولة الواعية بالكلفة بـ CostModel، وهو مُنتَج غير قابل للتغيير منفصل، مرتبط بمسألة عبر مُعرّفها. إبقاء طبقة الكلفة خارج ProblemSpec يتيح لمسألة وبيانات كلفتها أن تُؤرَّخا وتُسلسَلا بشكل مستقلّ. يَحزِم نموذج الكلفة خمسة عقود اختيارية:

  • ExecutionTimeMatrix — أزمنة معالجة الآلات غير المترابطة (p_ij) لعائلة R||Cmax. المصفوفة مبعثرة: زوج (task, machine) غائب يعني أن المهمة لا يمكن أن تعمل هناك، واستعلامه يطلق خطأً بدلًا من الافتراض إلى الصفر.
  • CompatibilityMask — مجموعة أهلية صريحة مهمة-إلى-آلة، تُبقى متمايزة عن مصفوفة التنفيذ حتى تتمكّن الأهلية والزمن المُجدوَل من التباعد.
  • SetupMatrix — أزمنة إعداد معتمِدة على التسلسل، مُفهرَسة بانتقال مهمة-إلى-مهمة أو نوع-إلى-نوع على آلة.
  • LoadModel — منحنى تنفيذ معتمِد على الحمل يُسقِط مستوى حملٍ على مضاعِف مدّة عبر استيفاء خطّي-قطعي أو درَجي بين نقاط كسر متزايدة بصرامة.
  • CommunicationModel — غرامات اتصال بين الموارد على رسم مبعثر؛ الاتصال على الآلة نفسها مجّاني، والأزواج بين-الآلات غير المُدرَجة تعود إلى غرامة افتراضية مُعلَنة.
from dispatchatlas.core import (
    CostModel,
    ProblemId,
    ResourceId,
    TaskId,
    execution_matrix_from_iterable,
)
 
cost_model = CostModel(
    problem_id=ProblemId("smoke"),
    execution_matrix=execution_matrix_from_iterable(
        [(TaskId("task-a"), ResourceId("cpu"), 1.0)]
    ),
)

🎯 الأهداف والاختزالات

تُسمّى عائلة الأهداف في OBJECTIVE_FAMILY، التي تسجّل المعنى والوحدة المعياريّين لكل هدف: makespan، الطاقة، الكلفة، الكربون، زمن الاستجابة، التأخّر، الإنصاف، حصّة المورد المهيمن (التشتّت بين حصّة المورد المهيمن للمستأجر الأكثر والأقلّ خدمةً — الحصّة العادلة متعدّدة المستأجرين)، الموثوقية، الأمان، المتانة، الإعداد، المكافأة غير الدقيقة (الحساب الاختياري المُنجَز فوق الجزء الإلزامي من المهام القابلة للتنفيذ جزئيًّا)، والمركّبات الموزونة. تَحمِل نتيجةً مقيسة VectorObjectiveValue، التي تحوي مدخلًا أو أكثر من ObjectiveValue (مرتّبة بالاسم) إضافةً إلى ObjectiveReduction صريح ووسم إفصاح. يُسكلِر اختزالا الجمع-الموزون وChebyshev المتّجهَ؛ أما الاختزالات غير المُسكلِرة (NONE، LEXICOGRAPHIC) فتطلق خطأً عند scalarize() كي يتعامل المستدعون مع الترتيب صراحةً.

تقرير الجدوى

يحوّل build_feasibility_report تقرير تحقّق جدول إلى FeasibilityReport مرئيّ للمراجِع: تصبح الانتهاكات الصارمة سجلّات InfeasibleRow لكل صفّ، وتراكم القيود المرنة المُسمّاة المنتهَكة مدخلات SoftConstraintPenalty موزونة. لا يقلب انتهاكٌ مرن feasible إلى False أبدًا.

📐 تقييم الأهداف والقيود والجبهات

تحسب طبقة الأهداف-والقيود كل هدف مُسمّى على حدة، فلا يُطوى أيٌّ منها في حزمة عامة. يشتقّ evaluate_objective makespan والتأخّر وإنصاف الحمل (مؤشّر Jain)، و — للنسخ المَوسومة بمستأجر — إنصاف حصّة-المورد-المهيمن مباشرةً من جدول، ويشتقّ الكلفة من مصفوفة زمن تنفيذ مرفقة وزمن الإعداد المعتمِد على التسلسل من مصفوفة إعداد مرفقة، ويختزل المكوّنات المحسوبة إلى مركّب موزون. الأهداف التي تحتاج نموذجًا لا تحمله النواة (الطاقة، الكربون، زمن الاستجابة، الموثوقية، الأمان، المتانة) تُعيد ObjectiveEvaluation بحالة DEFERRED ومسوّغ مُسمّى بدلًا من قيمة مُختلَقة. يَحمِل MultiObjectiveOutcome القيمَ القياسية والهدفَ المتّجهي وتقريرَ الجدوى عبر رحلة تسلسل-وعكس حتمية.

تضيف محاسبة القيود قيد مستوى الخدمة (SLA) المُسمّى بوصفه قيدًا من الدرجة الأولى بمسار خرق صارم (عدم جدوى) ومسار غرامة مرنة (غرامة موزونة متناسبة مع الخرق) معًا. يجمع ConstraintViolationSummary الانتهاكات الصارمة والغرامات المرنة ونتائج SLA وتشخيصات الإصلاح؛ ويُبلِّغ عن عدم الجدوى إما عند انتهاك قاعدة صارمة أو عند خرق SLA صارم.

تستخرج مساعِدات Pareto الجبهة غير المُهيمَن عليها وتُبلِّغ بمؤشّرات الجودة الأربعة المُسمّاة المختارة وفق Riquelme, Von Lücken & Barán (2015): الحجم الفائق (المؤشّر الأساسي)، وIGD+ (مؤشّر تقارب ضعيف-التوافق مع Pareto)، ومؤشّر إبسيلون الجمعي، والتشتّت (مؤشّر التنوّع). كل مؤشّر قابل للحساب على حدة. يبني frontier_data سجلّات جاهزة-للجبهة بعَلَم عدم-هيمنة للتحليل وعرض البوابة.

تُكمَّم المتانة بوصفها هدفًا قابلًا للقياس لا وسمَ موقف: يجمع evaluate_robustness قيمة هدفٍ واحد عبر مجموعة اضطرابات مُعلَنة صراحةً، إما بوصفها قيمة أسوأ-حالة أو بوصفها القيمة المعرّضة للخطر المشروطة (CVaR) لأسوأ ذيل. تُسجَّل مجموعة الاضطرابات والتجميع كلاهما على النتيجة.

⚠️ القيود

تُعرّف نواة الـ kernel عقود الكلفة والهدف والقيد، وطبقة الأهداف-والقيود التي تقيّمها؛ وهي لا تُحسِّن. الأهداف التي تحتاج نموذجًا لا تحمله النواة (الطاقة، الكربون، زمن الاستجابة، الموثوقية، الأمان، والمتانة) يُبلَّغ عنها بأنها مؤجَّلة مع مسوّغ مُسمّى بدلًا من تقديرها. يقيّم LoadModel منحناه المُعلَن وحده، ويحمل ObjectiveDefinition بيانات وصفية لا مُقيِّمًا.

🌱 الأصل والبذور

تحمل المُنتَجات المولَّدة سجلّات Provenance وArtifactHash وSourceReference وEnvironmentStamp وSeedLineage اختياريًّا. تُشتقّ تدفّقات البذور من إحداثيات مستقرّة:

from dispatchatlas.core import derive_seed
 
seed = derive_seed(42, "benchmark.smoke", 0)

البذرة الجذرية ومساحة الاسم والفهرس نفسها تُنتِج دائمًا البذرة المشتقّة نفسها.

📦 التسلسل

تتسلسل كائنات النواة عبر تخطيطات قانونية متوافقة مع JSON وأغلفة ArtifactEnvelope. تربط الأغلفة الحمولات بتجزئات المحتوى وتنسخ تلك التجزئة عائدةً إلى الأصل.

🔌 البروتوكولات

تعتمد الحزم الخارجية على بروتوكولات معرّفة في النواة:

  • BenchmarkProvider
  • Solver
  • ExperimentRunner
  • ResultRepository
  • DisclosurePolicy
  • AnalysisExporter

تُبقي هذه البروتوكولات واردات الحزم موجّهةً إلى الداخل، مع السماح في الوقت نفسه لحزم النسخ المرجعية والحلّالات والتجارب والتحليل الملموسة بأن تتركّب لاحقًا.