Skip to main content

katago_analysis/
request.rs

1use crate::*;
2
3/// A game record to be analyzed, along with analysis settings.
4#[derive(Debug, Clone)]
5pub struct AnalysisRequest {
6    /// The ruleset for this game.
7    pub rules: Rules,
8
9    /// The komi for this game.
10    pub komi: Option<f64>,
11
12    /// Bonus points white receives in handicap games.
13    pub white_handicap_bonus: Option<Bonus>,
14
15    /// The board width.
16    pub board_x_size: u8,
17
18    /// The board height.
19    pub board_y_size: u8,
20
21    /// The stones on the board before the first move.
22    pub initial_stones: Option<Vec<(Player, Coord)>>,
23
24    /// The player to move in the initial position.
25    pub initial_player: Option<Player>,
26
27    /// The moves played in the game.
28    pub moves: Vec<(Player, Move)>,
29
30    /// The maximum number of visits to use.
31    pub max_visits: Option<u32>,
32
33    /// Root policy temperature.
34    pub root_policy_temperature: Option<f64>,
35
36    /// Root FPU reduction max.
37    pub root_fpu_reduction_max: Option<f64>,
38
39    /// The maximum length of the principal variation to return, not including the first move.
40    pub analysis_pv_len: Option<usize>,
41
42    /// Whether to return the ownership prediction.
43    pub include_ownership: bool,
44
45    /// Whether to return the standard deviation of the ownership prediction.
46    pub include_ownership_stdev: bool,
47
48    /// Whether to return the ownership prediction for each move.
49    pub include_moves_ownership: bool,
50
51    /// Whether to return the standard deviation of the ownership prediction for each move.
52    pub include_moves_ownership_stdev: bool,
53
54    /// Whether to return the neural network policy output.
55    pub include_policy: bool,
56
57    /// Whether to return the number of visits for each position in the principal variation.
58    pub include_pv_visits: bool,
59
60    /// Whether to return the predicted probability that the game will have a void result.
61    pub include_no_result_value: bool,
62
63    /// Moves which are forbidden.
64    pub avoid_moves: Option<Vec<RestrictedMoves>>,
65
66    /// Moves which are allowed. If specified, all other moves are forbidden.
67    pub allow_moves: Option<Vec<RestrictedMoves>>,
68
69    /// Config overrides for this request.
70    pub override_settings: Option<Config>,
71
72    /// Report partial analysis results every this many seconds.
73    pub report_during_search_every: Option<f64>,
74
75    /// The priority of this request.
76    pub priority: Option<i32>,
77}
78
79impl AnalysisRequest {
80    /// Creates a new analysis request with the minimum required parameters.
81    pub fn new(
82        rules: Rules,
83        board_x_size: u8,
84        board_y_size: u8,
85        moves: Vec<(Player, Move)>,
86    ) -> Self {
87        Self {
88            rules,
89            komi: None,
90            white_handicap_bonus: None,
91            board_x_size,
92            board_y_size,
93            initial_stones: None,
94            initial_player: None,
95            moves,
96            max_visits: None,
97            root_policy_temperature: None,
98            root_fpu_reduction_max: None,
99            analysis_pv_len: None,
100            include_ownership: false,
101            include_ownership_stdev: false,
102            include_moves_ownership: false,
103            include_moves_ownership_stdev: false,
104            include_policy: false,
105            include_pv_visits: false,
106            include_no_result_value: false,
107            avoid_moves: None,
108            allow_moves: None,
109            override_settings: None,
110            report_during_search_every: None,
111            priority: None,
112        }
113    }
114
115    /// Converts this request into the lower-level equivalent used by the [`engine`] module.
116    ///
117    /// You probably don't need to use this unless you're directly using the lower-level API in the [`engine`] module.
118    pub fn into_engine_request(
119        self,
120        id: String,
121        analyze_turns: Vec<usize>,
122        priorities: Option<Vec<i32>>,
123    ) -> engine::AnalysisRequest {
124        engine::AnalysisRequest {
125            id,
126            rules: self.rules,
127            komi: self.komi,
128            white_handicap_bonus: self.white_handicap_bonus,
129            board_x_size: self.board_x_size,
130            board_y_size: self.board_y_size,
131            initial_stones: self.initial_stones.map(|s| {
132                s.into_iter()
133                    .map(|(p, c)| (p, c.to_gtp(self.board_y_size)))
134                    .collect()
135            }),
136            initial_player: self.initial_player,
137            moves: self
138                .moves
139                .into_iter()
140                .map(|(p, m)| (p, m.to_gtp(self.board_y_size)))
141                .collect(),
142            analyze_turns: Some(analyze_turns),
143            max_visits: self.max_visits,
144            root_policy_temperature: self.root_policy_temperature,
145            root_fpu_reduction_max: self.root_fpu_reduction_max,
146            analysis_pv_len: self.analysis_pv_len,
147            include_ownership: self.include_ownership,
148            include_ownership_stdev: self.include_ownership_stdev,
149            include_moves_ownership: self.include_moves_ownership,
150            include_moves_ownership_stdev: self.include_moves_ownership_stdev,
151            include_policy: self.include_policy,
152            include_pv_visits: self.include_pv_visits,
153            include_no_result_value: self.include_no_result_value,
154            avoid_moves: self.avoid_moves.map(|m| {
155                m.into_iter()
156                    .map(|rm| rm.into_engine_restricted_moves(self.board_y_size))
157                    .collect()
158            }),
159            allow_moves: self.allow_moves.map(|m| {
160                m.into_iter()
161                    .map(|rm| rm.into_engine_restricted_moves(self.board_y_size))
162                    .collect()
163            }),
164            override_settings: self.override_settings,
165            report_during_search_every: self.report_during_search_every,
166            priority: self.priority,
167            priorities,
168        }
169    }
170
171    /// Sets komi.
172    pub fn with_komi(mut self, komi: f64) -> Self {
173        self.komi = Some(komi);
174        self
175    }
176
177    /// Sets white's handicap bonus.
178    pub fn with_white_handicap_bonus(mut self, bonus: Bonus) -> Self {
179        self.white_handicap_bonus = Some(bonus);
180        self
181    }
182
183    /// Sets the initial position before the first move.
184    pub fn with_initial_stones(mut self, initial_stones: Vec<(Player, Coord)>) -> Self {
185        self.initial_stones = Some(initial_stones);
186        self
187    }
188
189    /// Sets the player to move in the initial position.
190    pub fn with_initial_player(mut self, initial_player: Player) -> Self {
191        self.initial_player = Some(initial_player);
192        self
193    }
194
195    /// Sets the maximum number of visits to use.
196    pub fn with_max_visits(mut self, max_visits: u32) -> Self {
197        self.max_visits = Some(max_visits);
198        self
199    }
200
201    /// Sets the root policy temperature.
202    pub fn with_root_policy_temperature(mut self, root_policy_temperature: f64) -> Self {
203        self.root_policy_temperature = Some(root_policy_temperature);
204        self
205    }
206
207    /// Sets the root FPU reduction max.
208    pub fn with_root_fpu_reduction_max(mut self, root_fpu_reduction_max: f64) -> Self {
209        self.root_fpu_reduction_max = Some(root_fpu_reduction_max);
210        self
211    }
212
213    /// Sets the maximum length of the principal variation to return, not including the first move.
214    pub fn with_analysis_pv_len(mut self, analysis_pv_len: usize) -> Self {
215        self.analysis_pv_len = Some(analysis_pv_len);
216        self
217    }
218
219    /// Includes the ownership prediction.
220    pub fn with_ownership(mut self) -> Self {
221        self.include_ownership = true;
222        self
223    }
224
225    /// Includes the standard deviation of the ownership prediction.
226    pub fn with_ownership_stdev(mut self) -> Self {
227        self.include_ownership_stdev = true;
228        self
229    }
230
231    /// Includes the ownership prediction for each move.
232    pub fn with_moves_ownership(mut self) -> Self {
233        self.include_moves_ownership = true;
234        self
235    }
236
237    /// Includes the standard deviation of the ownership prediction for each move.
238    pub fn with_moves_ownership_stdev(mut self) -> Self {
239        self.include_moves_ownership_stdev = true;
240        self
241    }
242
243    /// Includes the neural network policy output.
244    pub fn with_policy(mut self) -> Self {
245        self.include_policy = true;
246        self
247    }
248
249    /// Includes the number of visits for each position in the principal variation.
250    pub fn with_pv_visits(mut self) -> Self {
251        self.include_pv_visits = true;
252        self
253    }
254
255    /// Includes the predicted probability that the game will have a void result.
256    pub fn with_no_result_value(mut self) -> Self {
257        self.include_no_result_value = true;
258        self
259    }
260
261    /// Sets moves which are forbidden.
262    pub fn with_avoid_moves(mut self, avoid_moves: Vec<RestrictedMoves>) -> Self {
263        self.avoid_moves = Some(avoid_moves);
264        self
265    }
266
267    /// Sets moves which are allowed.
268    pub fn with_allow_moves(mut self, allow_moves: Vec<RestrictedMoves>) -> Self {
269        self.allow_moves = Some(allow_moves);
270        self
271    }
272
273    /// Overrides config settings for this request.
274    pub fn with_override_settings(mut self, config: Config) -> Self {
275        self.override_settings = Some(config);
276        self
277    }
278
279    /// Gets partial analysis results every this many seconds.
280    pub fn with_report_during_search_every(mut self, seconds: f64) -> Self {
281        self.report_during_search_every = Some(seconds);
282        self
283    }
284
285    /// Sets the priority of this request.
286    pub fn with_priority(mut self, priority: i32) -> Self {
287        self.priority = Some(priority);
288        self
289    }
290}
291
292/// A list of moves that are either forbidden with [`AnalysisRequest::avoid_moves`] or allowed with
293/// [`AnalysisRequest::allow_moves`].
294#[derive(Debug, Clone)]
295pub struct RestrictedMoves {
296    /// The player the move restriction applies to.
297    pub player: Player,
298
299    /// The list of moves.
300    pub moves: Vec<Move>,
301
302    /// The search depth within which the restriction applies.
303    pub until_depth: u32,
304}
305
306impl RestrictedMoves {
307    /// Converts this restriction into the lower-level equivalent used by the [`engine`] module.
308    ///
309    /// You probably don't need to use this unless you're directly using the lower-level API in the [`engine`] module.
310    pub fn into_engine_restricted_moves(self, height: u8) -> engine::RestrictedMoves {
311        engine::RestrictedMoves {
312            player: self.player,
313            moves: self.moves.into_iter().map(|m| m.to_gtp(height)).collect(),
314            until_depth: self.until_depth,
315        }
316    }
317}