[Canonical page](<https://docs.dhtmlx.com/planning-engine/net/api/project-solve/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Project.Solve

Schedules a [`Project`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/project.md>) and accepts the scheduled dates as its baseline. Pass a [`ProjectData`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/project-data.md>) to load a project, or `null` to reschedule after [`Apply`](<https://docs.dhtmlx.com/planning-engine/net/api/project-apply.md>). The other read-only calls ([`Preview`](<https://docs.dhtmlx.com/planning-engine/net/api/project-preview.md>), [`Evaluate`](<https://docs.dhtmlx.com/planning-engine/net/api/project-evaluate.md>), [`SuggestAssignments`](<https://docs.dhtmlx.com/planning-engine/net/api/project-suggest-assignments.md>) and the rest) need a solved project.

For a one-shot run that keeps no state, use [`Engine.Schedule`](<https://docs.dhtmlx.com/planning-engine/net/api/engine-schedule.md>).

## Signature

```csharp
public ScheduleResult Solve(ProjectData? data, SolveOptions options)
```

Synchronous and CPU-only. Changes the project's state.

## Parameters

| Name | Type | Description |
|---|---|---|
| `data` | [`ProjectData`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/project-data.md>)`?` | Replacement data, or `null` to schedule the current state |
| `options` | [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/solve-options.md>) | Subtree, analytics and reporting switches |

## Behavior

- A non-null `data` is deep-copied, validated, installed, scheduled and accepted. The previous data is discarded. Later changes to the caller's [`ProjectData`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/project-data.md>) don't reach the project. [`ProjectOptions.Validation`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/project-options.md>) decides whether invalid data is rejected or repaired.
- `null` schedules the current state when it has unsolved edits. When the project is already solved with equal `options`, it returns the same cached result object without scheduling again. The cache key is the whole [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/solve-options.md>) value, compared by value.

Tasks touched by successful [`Apply`](<https://docs.dhtmlx.com/planning-engine/net/api/project-apply.md>) calls since the last solve appear in [`Updates`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/schedule-result.md#updates>) as direct updates, even when the planner leaves them where the edit put them. A cyclic project returns unchanged dates and keeps those tasks pending.

The result's [`BaselineId`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/schedule-result.md#baselineid>) names the accepted baseline. It changes only when the data or the dates change, so solving an unchanged state keeps it.

## Returns

The [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/schedule-result.md>). The project keeps the result as its baseline and shares it with clones. A later call can return the same object. Treat it as read-only, or call `DeepClone()` before modifying it.

## Errors

| Error | When |
|---|---|
| [`InputException`](<https://docs.dhtmlx.com/planning-engine/net/api/core/errors/input-exception.md>) | `data` fails validation, or [`options.Subtree`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/solve-options.md#subtree>) names an unknown or unscheduled task (`Path == "subtree.task"`). The previous state and cached result are kept. |
| [`ProjectException`](<https://docs.dhtmlx.com/planning-engine/net/api/core/errors/project-exception.md>) `NeedsResync` | `data` is `null` after an `Apply` rejected an operation and no `Solve(data, …)` followed |
| `ArgumentNullException` | `options` is `null` |

## Example

Load a project, commit an edit and reschedule it.

```csharp
using Plen;

var monday = Moment.FromYmdHm(2026, 8, 10, 8, 0) ?? throw new InvalidOperationException("invalid date");
var data = new ProjectData
{
    Tasks = [new TaskData(1) { StartDate = monday, Duration = 2.0 }],
};

var options = new SolveOptions();
var project = new Project();
var loaded = project.Solve(data, options);

// Nothing changed: the cached result comes back with the same baseline.
var again = project.Solve(null, options);
Console.WriteLine(again.BaselineId == loaded.BaselineId); // True

var changes = new SchedulingChanges();
changes.Tasks.Update.Add(new TaskUpdate(1) { Duration = 3.0 });
project.Apply(changes);

var result = project.Solve(null, options);
foreach (var update in result.Updates)
    Console.WriteLine($"task {update.Id}: {update.StartDate} .. {update.EndDate}"); // task 1: 2026-08-10 08:00 .. 2026-08-13 08:00
```

## Related

- [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/solve-options.md>) - the options
- [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/schedule-result.md>) - the returned result
- [`Engine.Schedule`](<https://docs.dhtmlx.com/planning-engine/net/api/engine-schedule.md>) - the one-shot call that keeps no state
- [Scheduling a project](<https://docs.dhtmlx.com/planning-engine/net/scheduling/scheduling-a-project.md>) - loading, caching and solve options
- [Editing a project](<https://docs.dhtmlx.com/planning-engine/net/live-projects/editing-a-project.md>) - committing edits and rescheduling
