Skip to content

Commit

Permalink
Merge pull request #1188 from lichess-org/analysis_search_time
Browse files Browse the repository at this point in the history
Implement analysis search time
  • Loading branch information
veloce authored Nov 26, 2024
2 parents 5a08dcc + a7406f4 commit 795bc01
Show file tree
Hide file tree
Showing 15 changed files with 374 additions and 277 deletions.
20 changes: 20 additions & 0 deletions lib/src/model/analysis/analysis_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ class AnalysisController extends _$AnalysisController
options: EvaluationOptions(
multiPv: prefs.numEvalLines,
cores: prefs.numEngineCores,
searchTime: prefs.engineSearchTime,
),
)
.then((_) {
Expand Down Expand Up @@ -389,6 +390,7 @@ class AnalysisController extends _$AnalysisController
options: EvaluationOptions(
multiPv: prefs.numEvalLines,
cores: prefs.numEngineCores,
searchTime: prefs.engineSearchTime,
),
);
_startEngineEval();
Expand All @@ -407,6 +409,7 @@ class AnalysisController extends _$AnalysisController
EvaluationOptions(
multiPv: numEvalLines,
cores: ref.read(analysisPreferencesProvider).numEngineCores,
searchTime: ref.read(analysisPreferencesProvider).engineSearchTime,
),
);

Expand All @@ -432,6 +435,23 @@ class AnalysisController extends _$AnalysisController
EvaluationOptions(
multiPv: ref.read(analysisPreferencesProvider).numEvalLines,
cores: numEngineCores,
searchTime: ref.read(analysisPreferencesProvider).engineSearchTime,
),
);

_startEngineEval();
}

void setEngineSearchTime(Duration searchTime) {
ref
.read(analysisPreferencesProvider.notifier)
.setEngineSearchTime(searchTime);

ref.read(evaluationServiceProvider).setOptions(
EvaluationOptions(
multiPv: ref.read(analysisPreferencesProvider).numEvalLines,
cores: ref.read(analysisPreferencesProvider).numEngineCores,
searchTime: searchTime,
),
);

Expand Down
39 changes: 39 additions & 0 deletions lib/src/model/analysis/analysis_preferences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ class AnalysisPreferences extends _$AnalysisPreferences
),
);
}

Future<void> setEngineSearchTime(Duration engineSearchTime) {
return save(
state.copyWith(
engineSearchTime: engineSearchTime,
),
);
}
}

@Freezed(fromJson: true, toJson: true)
Expand All @@ -107,6 +115,12 @@ class AnalysisPrefs with _$AnalysisPrefs implements Serializable {
@Assert('numEvalLines >= 0 && numEvalLines <= 3') required int numEvalLines,
@Assert('numEngineCores >= 1 && numEngineCores <= maxEngineCores')
required int numEngineCores,
@JsonKey(
defaultValue: _searchTimeDefault,
fromJson: _searchTimeFromJson,
toJson: _searchTimeToJson,
)
required Duration engineSearchTime,
}) = _AnalysisPrefs;

static const defaults = AnalysisPrefs(
Expand All @@ -118,9 +132,34 @@ class AnalysisPrefs with _$AnalysisPrefs implements Serializable {
showPgnComments: true,
numEvalLines: 2,
numEngineCores: 1,
engineSearchTime: Duration(seconds: 10),
);

factory AnalysisPrefs.fromJson(Map<String, dynamic> json) {
return _$AnalysisPrefsFromJson(json);
}
}

Duration _searchTimeDefault() {
return const Duration(seconds: 10);
}

Duration _searchTimeFromJson(int seconds) {
return Duration(seconds: seconds);
}

int _searchTimeToJson(Duration duration) {
return duration.inSeconds;
}

const kAvailableEngineSearchTimes = [
Duration(seconds: 4),
Duration(seconds: 6),
Duration(seconds: 8),
Duration(seconds: 10),
Duration(seconds: 12),
Duration(seconds: 15),
Duration(seconds: 20),
Duration(seconds: 30),
Duration(hours: 1),
];
2 changes: 1 addition & 1 deletion lib/src/model/common/eval.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class ClientEval with _$ClientEval implements Eval {
required int nodes,
required IList<PvData> pvs,
required int millis,
required int maxDepth,
required Duration searchTime,
int? cp,
int? mate,
}) = _ClientEval;
Expand Down
9 changes: 5 additions & 4 deletions lib/src/model/engine/evaluation_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import 'work.dart';
part 'evaluation_service.g.dart';
part 'evaluation_service.freezed.dart';

const kMaxEngineDepth = 22;
final maxEngineCores = max(Platform.numberOfProcessors - 1, 1);
final defaultEngineCores =
min((Platform.numberOfProcessors / 2).ceil(), maxEngineCores);
Expand All @@ -45,6 +44,7 @@ class EvaluationService {
EvaluationOptions _options = EvaluationOptions(
multiPv: 1,
cores: defaultEngineCores,
searchTime: const Duration(seconds: 10),
);

static const _defaultState =
Expand Down Expand Up @@ -133,17 +133,17 @@ class EvaluationService {
variant: context.variant,
threads: _options.cores,
hashSize: maxMemory,
maxDepth: kMaxEngineDepth,
searchTime: _options.searchTime,
multiPv: _options.multiPv,
path: path,
initialPosition: context.initialPosition,
steps: IList(steps),
);

// cancel evaluation if we already have a cached eval at max depth
// cancel evaluation if we already have a cached eval at max search time
final cachedEval =
work.steps.isEmpty ? initialPositionEval : work.evalCache;
if (cachedEval != null && cachedEval.depth >= kMaxEngineDepth) {
if (cachedEval != null && cachedEval.searchTime >= _options.searchTime) {
_state.value = (
engineName: _state.value.engineName,
state: _state.value.state,
Expand Down Expand Up @@ -231,5 +231,6 @@ class EvaluationOptions with _$EvaluationOptions {
const factory EvaluationOptions({
required int multiPv,
required int cores,
required Duration searchTime,
}) = _EvaluationOptions;
}
17 changes: 3 additions & 14 deletions lib/src/model/engine/uci_protocol.dart
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class UCIProtocol {
if (multiPv == 1) {
_currentEval = ClientEval(
position: _work!.position,
maxDepth: _work!.maxDepth,
searchTime: Duration(milliseconds: elapsedMs),
depth: depth,
nodes: nodes,
cp: isMate ? null : ev,
Expand All @@ -169,14 +169,7 @@ class UCIProtocol {
if (multiPv == _expectedPvs && _currentEval != null) {
_evalController.sink.add((_work!, _currentEval!));

// Depth limits are nice in the user interface, but in clearly decided
// positions the usual depth limits are reached very quickly due to
// pruning. Therefore not using `go depth ${_work.maxDepth}` and
// manually ensuring Stockfish gets to spend a minimum amount of
// time/nodes on each position.
if (depth >= _work!.maxDepth &&
elapsedMs > 8000 &&
nodes > 4000 * math.exp(_work!.maxDepth * 0.3)) {
if (elapsedMs > _work!.searchTime.inMilliseconds) {
_stop();
}
}
Expand Down Expand Up @@ -219,11 +212,7 @@ class UCIProtocol {
),
].join(' '),
);
_sendAndLog(
_work!.maxDepth >= 99
? 'go depth $maxPlies' // 'go infinite' would not finish even if entire tree search completed
: 'go movetime 60000',
);
_sendAndLog('go movetime ${_work!.searchTime.inMilliseconds}');
_isComputing.value = true;
} else {
_isComputing.value = false;
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/engine/work.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Work with _$Work {
required int threads,
int? hashSize,
required UciPath path,
required int maxDepth,
required Duration searchTime,
required int multiPv,
bool? threatMode,
required Position initialPosition,
Expand Down
21 changes: 21 additions & 0 deletions lib/src/model/study/study_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ class StudyController extends _$StudyController implements PgnTreeNotifier {
options: EvaluationOptions(
multiPv: prefs.numEvalLines,
cores: prefs.numEngineCores,
searchTime: ref.read(analysisPreferencesProvider).engineSearchTime,
),
)
.then((_) {
Expand Down Expand Up @@ -350,6 +351,8 @@ class StudyController extends _$StudyController implements PgnTreeNotifier {
options: EvaluationOptions(
multiPv: prefs.numEvalLines,
cores: prefs.numEngineCores,
searchTime:
ref.read(analysisPreferencesProvider).engineSearchTime,
),
);
_startEngineEval();
Expand All @@ -370,6 +373,7 @@ class StudyController extends _$StudyController implements PgnTreeNotifier {
EvaluationOptions(
multiPv: numEvalLines,
cores: ref.read(analysisPreferencesProvider).numEngineCores,
searchTime: ref.read(analysisPreferencesProvider).engineSearchTime,
),
);

Expand All @@ -395,6 +399,23 @@ class StudyController extends _$StudyController implements PgnTreeNotifier {
EvaluationOptions(
multiPv: ref.read(analysisPreferencesProvider).numEvalLines,
cores: numEngineCores,
searchTime: ref.read(analysisPreferencesProvider).engineSearchTime,
),
);

_startEngineEval();
}

void setEngineSearchTime(Duration searchTime) {
ref
.read(analysisPreferencesProvider.notifier)
.setEngineSearchTime(searchTime);

ref.read(evaluationServiceProvider).setOptions(
EvaluationOptions(
multiPv: ref.read(analysisPreferencesProvider).numEvalLines,
cores: ref.read(analysisPreferencesProvider).numEngineCores,
searchTime: searchTime,
),
);

Expand Down
18 changes: 7 additions & 11 deletions lib/src/view/analysis/analysis_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import 'package:lichess_mobile/src/view/engine/engine_depth.dart';
import 'package:lichess_mobile/src/view/engine/engine_gauge.dart';
import 'package:lichess_mobile/src/view/engine/engine_lines.dart';
import 'package:lichess_mobile/src/widgets/adaptive_action_sheet.dart';
import 'package:lichess_mobile/src/widgets/adaptive_bottom_sheet.dart';
import 'package:lichess_mobile/src/widgets/bottom_bar.dart';
import 'package:lichess_mobile/src/widgets/bottom_bar_button.dart';
import 'package:lichess_mobile/src/widgets/buttons.dart';
Expand Down Expand Up @@ -88,16 +87,13 @@ class _AnalysisScreenState extends ConsumerState<AnalysisScreen>
controller: _tabController,
),
AppBarIconButton(
onPressed: () => showAdaptiveBottomSheet<void>(
context: context,
isScrollControlled: true,
showDragHandle: true,
isDismissible: true,
constraints: BoxConstraints(
minHeight: MediaQuery.sizeOf(context).height * 0.5,
),
builder: (_) => AnalysisSettings(widget.options),
),
onPressed: () {
pushPlatformRoute(
context,
title: context.l10n.settingsSettings,
builder: (_) => AnalysisSettings(widget.options),
);
},
semanticsLabel: context.l10n.settingsSettings,
icon: const Icon(Icons.settings),
),
Expand Down
Loading

0 comments on commit 795bc01

Please sign in to comment.