From 0ec4d89a8bccc86c90acfcb4186ca6e08f18c599 Mon Sep 17 00:00:00 2001 From: Alan Scherger Date: Mon, 19 Oct 2026 09:18:01 -0500 Subject: [PATCH] feat: Add a learned correction to the ranking stage A small LambdaRank tree ensemble (150 trees, 7 leaves) rescales each candidate's boosted score by exp(correction), using 21 signals the ranking stage already computes: list ranks and scores, fusion, the file/stem/definition boosts, path penalty and file shape. It is evaluated with numpy from the packaged ranking/ranker.json (69 KB), so there is no new runtime dependency. search() is split into score_candidates(), which returns every intermediate score as RankingSignals, and the final rerank. apply_query_boost is unchanged; query_boost_deltas exposes its stem and definition parts as features. Setting SEMBLE_LEARNED_RANKER=0 restores the hand-tuned ranking exactly. benchmarks/train_ranker.py retrains the model from the benchmark annotations (LightGBM via `uv run --with lightgbm`, never a dependency) and checks the numpy evaluator against LightGBM before writing. Only the best-ranked chunk per target is labelled relevant. Leave-one-repo-out on the benchmark: NDCG@10 0.8550 -> 0.8627 (+0.78). On 840 commit-message queries from 21 repos the model never trained on: +0.84 [+0.40, +1.30]. Median query latency +1.8 ms on an M5 Max. --- benchmarks/train_ranker.py | 171 ++++++++++++++++++++++++++++ pyproject.toml | 2 +- src/semble/ranking/boosting.py | 27 +++++ src/semble/ranking/learned.py | 200 +++++++++++++++++++++++++++++++++ src/semble/ranking/ranker.json | 1 + src/semble/search.py | 73 +++++++++--- tests/test_learned_ranker.py | 82 ++++++++++++++ 7 files changed, 539 insertions(+), 17 deletions(-) create mode 100644 benchmarks/train_ranker.py create mode 100644 src/semble/ranking/learned.py create mode 100644 src/semble/ranking/ranker.json create mode 100644 tests/test_learned_ranker.py diff --git a/benchmarks/train_ranker.py b/benchmarks/train_ranker.py new file mode 100644 index 00000000..6163f8a8 --- /dev/null +++ b/benchmarks/train_ranker.py @@ -0,0 +1,171 @@ +"""Train the learned ranker (src/semble/ranking/ranker.json) on the benchmark annotations. + +LightGBM is only needed here, not at query time: + + uv run --with lightgbm python -m benchmarks.train_ranker --cv # leave-one-repo-out NDCG@10, no file written + uv run --with lightgbm python -m benchmarks.train_ranker # train on every repo and write ranker.json + +For each query, the candidate pool and features come from the same code path search uses +(``score_candidates`` + ``ranking_features``). The model is a LambdaRank tree ensemble that learns a log-scale +correction to the boosted score (``init_score = log(boosted / max boosted)``), so an empty model reproduces +today's ranking. Only the best-ranked chunk covering each annotated target is labelled relevant: labelling every +chunk of a whole-file target teaches the model to promote large files. +""" + +import argparse +import json +import os +import sys +from pathlib import Path + +import numpy as np + +from benchmarks.data import add_filter_args, grouped_tasks, load_filtered_tasks, target_matches_location +from benchmarks.metrics import ndcg_at_k, target_rank +from semble import SembleIndex +from semble.ranking import rerank_topk +from semble.ranking.learned import FEATURES, RankingSignals, TreeEnsemble, ranking_features +from semble.search import score_candidates +from semble.types import SearchResult + +_TOP_K = 10 +_OUT = Path(__file__).resolve().parent.parent / "src" / "semble" / "ranking" / "ranker.json" +_PARAMS = { + "objective": "lambdarank", + "n_estimators": 150, + "learning_rate": 0.03, + "num_leaves": 7, + "min_child_samples": 200, + "reg_lambda": 10.0, + "lambdarank_truncation_level": 10, + "deterministic": True, + "force_row_wise": True, + "verbose": -1, +} + + +def _collect(repo_filter: list[str] | None, language_filter: list[str] | None) -> list[dict]: + """Return one record per query: repo, task, signals, pool, features and first-hit labels.""" + specs, tasks = load_filtered_tasks(repo_filter, language_filter) + records = [] + for repo, repo_tasks in sorted(grouped_tasks(tasks).items()): + index = SembleIndex.from_path(specs[repo].benchmark_dir) + for task in repo_tasks: + signals = score_candidates( + task.query, index.model, index._semantic_index, index._bm25_index, index.chunks, _TOP_K + ) + pool, features = ranking_features(signals) + labels = np.zeros(len(pool), dtype=int) + for target in task.all_relevant: + for i, chunk in enumerate(pool): + if target_matches_location(chunk.file_path, chunk.start_line, chunk.end_line, target): + labels[i] = 1 + break + records.append({"repo": repo, "task": task, "signals": signals, "pool": pool, "x": features, "y": labels}) + print(f" {repo}: {len(repo_tasks)} queries", file=sys.stderr) + return records + + +def _init_score(x: np.ndarray) -> np.ndarray: + return np.log(np.maximum(x[:, FEATURES.index("final_rel")], 1e-9)) + + +def _fit(records: list[dict]): # noqa: ANN202 + import lightgbm as lgb + + model = lgb.LGBMRanker(**_PARAMS) + x = np.vstack([r["x"] for r in records]) + model.fit( + x, np.concatenate([r["y"] for r in records]), group=[len(r["pool"]) for r in records], init_score=_init_score(x) + ) + return model + + +def _ndcg(record: dict, scores: dict) -> float: + signals: RankingSignals = record["signals"] + ranked = rerank_topk(scores, _TOP_K, penalise_paths=signals.alpha < 1.0) + results = [SearchResult(chunk=c, score=s) for c, s in ranked] + task = record["task"] + ranks = [r for t in task.all_relevant if (r := target_rank(results, t)) is not None] + return ndcg_at_k(ranks, len(task.all_relevant), _TOP_K) + + +def _corrected(record: dict, correction: np.ndarray) -> dict: + boosted = record["signals"].boosted + return {c: boosted[c] * float(np.exp(d)) for c, d in zip(record["pool"], correction)} + + +def to_ensemble_dict(booster) -> dict: # noqa: ANN001 + """Convert a LightGBM booster to ranker.json's flat per-tree node arrays.""" + trees = [] + for info in booster.dump_model()["tree_info"]: + feature: list[int] = [] + threshold: list[float] = [] + left: list[int] = [] + right: list[int] = [] + value: list[float] = [] + + def add(node: dict) -> int: + nid = len(feature) + feature.append(-1) + threshold.append(0.0) + left.append(0) + right.append(0) + value.append(0.0) # noqa: E702 + if "leaf_value" in node: + value[nid] = float(node["leaf_value"]) + return nid + if node.get("decision_type", "<=") != "<=": + raise ValueError(f"Unsupported split {node.get('decision_type')!r}") + feature[nid] = int(node["split_feature"]) + threshold[nid] = float(node["threshold"]) + left[nid] = add(node["left_child"]) + right[nid] = add(node["right_child"]) + return nid + + add(info["tree_structure"]) + trees.append({"feature": feature, "threshold": threshold, "left": left, "right": right, "value": value}) + return {"features": list(FEATURES), "params": {k: v for k, v in _PARAMS.items() if k != "verbose"}, "trees": trees} + + +def main() -> None: + """Train, cross-validate, or export the learned ranker.""" + parser = argparse.ArgumentParser(description="Train semble's learned ranker on the benchmark annotations.") + add_filter_args(parser) + parser.add_argument("--cv", action="store_true", help="Report leave-one-repo-out NDCG@10 instead of writing.") + parser.add_argument("--output", type=Path, default=_OUT) + args = parser.parse_args() + + # Features must come from the hand-tuned ranking only, never from a previously shipped model. + os.environ["SEMBLE_LEARNED_RANKER"] = "0" + records = _collect(args.repo or None, args.language or None) + print(f"{len(records)} queries, {sum(len(r['pool']) for r in records)} candidates", file=sys.stderr) + + if args.cv: + repos = sorted({r["repo"] for r in records}) + base, learned = [], [] + for repo in repos: + model = _fit([r for r in records if r["repo"] != repo]) + for r in (r for r in records if r["repo"] == repo): + base.append(_ndcg(r, r["signals"].boosted)) + learned.append(_ndcg(r, _corrected(r, model.predict(r["x"])))) + print( + f"leave-one-repo-out NDCG@10 over {len(base)} queries: hand-tuned {np.mean(base):.4f}, " + f"learned {np.mean(learned):.4f} ({np.mean(learned) - np.mean(base):+.4f})", + file=sys.stderr, + ) + return + + model = _fit(records) + payload = to_ensemble_dict(model.booster_) + ensemble = TreeEnsemble.from_dict(payload) + x = np.vstack([r["x"] for r in records]) + drift = float(np.abs(ensemble.predict(x) - model.predict(x)).max()) + if drift > 1e-6: + raise RuntimeError(f"numpy evaluator disagrees with LightGBM by {drift:g}") + args.output.write_text(json.dumps(payload, separators=(",", ":")) + "\n") + print(f"wrote {args.output} ({len(payload['trees'])} trees, max |numpy - lightgbm| = {drift:.2g})", file=sys.stderr) + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index 5e845098..c1390c4b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ where = ["src"] include = ["semble*"] [tool.setuptools.package-data] -semble = ["py.typed", "agents/*.md", "agents/*.toml"] +semble = ["py.typed", "agents/*.md", "agents/*.toml", "ranking/*.json"] [tool.setuptools_scm] # can be empty if no extra settings are needed, presence enables setuptools_scm diff --git a/src/semble/ranking/boosting.py b/src/semble/ranking/boosting.py index dd88f402..ac20560d 100644 --- a/src/semble/ranking/boosting.py +++ b/src/semble/ranking/boosting.py @@ -109,6 +109,33 @@ def apply_query_boost( return boosted +def query_boost_deltas( + combined_scores: dict[Chunk, float], + query: str, + all_chunks: list[Chunk], +) -> tuple[dict[Chunk, float], dict[Chunk, float]]: + """Return the (path-stem, definition) amounts apply_query_boost adds to each chunk, as separate dicts. + + Chunks the definition scan adds from outside the candidates appear with their full boost. + Used as learned-ranker features; apply_query_boost itself is unchanged. + """ + if not combined_scores: + return {}, {} + max_score = max(combined_scores.values()) + + def _delta(boost: Callable[[dict[Chunk, float]], None]) -> dict[Chunk, float]: + boosted = dict(combined_scores) + boost(boosted) + return {c: v - combined_scores.get(c, 0.0) for c, v in boosted.items() if v != combined_scores.get(c, 0.0)} + + if is_symbol_query(query): + return {}, _delta(lambda b: _boost_symbol_definitions(b, query, max_score, all_chunks)) + return ( + _delta(lambda b: _boost_stem_matches(b, query, max_score)), + _delta(lambda b: _boost_embedded_symbols(b, query, max_score, all_chunks)), + ) + + def boost_multi_chunk_files(scores: dict[Chunk, float]) -> None: """Promote files with multiple high-scoring chunks by boosting their top chunk (in-place).""" if not scores: diff --git a/src/semble/ranking/learned.py b/src/semble/ranking/learned.py new file mode 100644 index 00000000..e34811ac --- /dev/null +++ b/src/semble/ranking/learned.py @@ -0,0 +1,200 @@ +"""Learned reranking of the candidate pool: a small gradient-boosted tree ensemble, evaluated with numpy. + +The model predicts a log-scale correction to each candidate's boosted score from signals the ranking stage +already computes (list ranks and scores, fusion, boosts, path penalty, file shape). It is trained offline by +``benchmarks/train_ranker.py`` and shipped as ``ranker.json``; no ML library is needed at query time. +""" + +from __future__ import annotations + +import functools +import json +import os +from dataclasses import dataclass +from importlib import resources +from pathlib import Path + +import numpy as np +import numpy.typing as npt + +from semble.ranking.penalties import _file_path_penalty +from semble.types import Chunk + +FEATURES: tuple[str, ...] = ( + "final_rank", + "final_rel", + "fused_rank", + "fused_rel", + "file_boost_rel", + "stem_boost_rel", + "definition_boost_rel", + "path_penalty", + "is_penalised_path", + "semantic_rank", + "semantic_score", + "semantic_rel", + "in_semantic", + "bm25_rank", + "bm25_rel", + "in_bm25", + "in_both", + "file_chunks_in_pool", + "file_best_final_rank", + "is_file_best", + "path_depth", +) +_MISSING_LIST_RANK = 100 +_MISSING_FUSED_RANK = 200 + + +@dataclass(frozen=True) +class RankingSignals: + """Every intermediate score of one query's ranking stage, as produced by ``semble.search``.""" + + alpha: float + semantic: dict[Chunk, float] # raw cosine similarity, in rank order + bm25: dict[Chunk, float] # raw BM25 score, in rank order + fused: dict[Chunk, float] # alpha-weighted RRF fusion + file_boost: dict[Chunk, float] # added by boost_multi_chunk_files + stem_boost: dict[Chunk, float] # added by the NL path-stem boost + definition_boost: dict[Chunk, float] # added by the symbol-definition boosts + boosted: dict[Chunk, float] # final score before path penalties and file saturation + + +def ranking_features(signals: RankingSignals) -> tuple[list[Chunk], npt.NDArray[np.float64]]: + """Return the candidate pool (best boosted score first) and its feature matrix, columns as in FEATURES.""" + boosted = signals.boosted + chunks = sorted(boosted, key=lambda c: -boosted[c]) + if not chunks: + return [], np.empty((0, len(FEATURES))) + semantic_rank = {c: r for r, c in enumerate(signals.semantic, 1)} + bm25_rank = {c: r for r, c in enumerate(signals.bm25, 1)} + semantic_top = next(iter(signals.semantic.values()), 1.0) or 1.0 + bm25_top = next(iter(signals.bm25.values()), 1.0) or 1.0 + fused_rank = {c: r for r, c in enumerate(sorted(signals.fused, key=lambda c: -signals.fused[c]), 1)} + fused_max = max(signals.fused.values(), default=1.0) or 1.0 + boosted_max = boosted[chunks[0]] or 1.0 + file_ranks: dict[str, list[int]] = {} + for rank, chunk in enumerate(chunks, 1): + file_ranks.setdefault(chunk.file_path, []).append(rank) + + rows = [] + for rank, chunk in enumerate(chunks, 1): + penalty = _file_path_penalty(chunk.file_path) + ranks_in_file = file_ranks[chunk.file_path] + rows.append( + ( + rank, + boosted[chunk] / boosted_max, + fused_rank.get(chunk, _MISSING_FUSED_RANK), + signals.fused.get(chunk, 0.0) / fused_max, + signals.file_boost.get(chunk, 0.0) / fused_max, + signals.stem_boost.get(chunk, 0.0) / fused_max, + signals.definition_boost.get(chunk, 0.0) / fused_max, + penalty, + float(penalty < 1.0), + semantic_rank.get(chunk, _MISSING_LIST_RANK), + signals.semantic.get(chunk, 0.0), + signals.semantic.get(chunk, 0.0) / semantic_top, + float(chunk in semantic_rank), + bm25_rank.get(chunk, _MISSING_LIST_RANK), + signals.bm25.get(chunk, 0.0) / bm25_top, + float(chunk in bm25_rank), + float(chunk in semantic_rank and chunk in bm25_rank), + len(ranks_in_file), + ranks_in_file[0], + float(ranks_in_file[0] == rank), + len(Path(chunk.file_path).parts), + ) + ) + return chunks, np.asarray(rows, dtype=np.float64) + + +class TreeEnsemble: + """Sum of regression trees, evaluated for all rows and all trees at once. + + Trees are stored as padded node arrays: an internal node goes left when ``x[feature] <= threshold``; + a leaf has ``feature == -1`` and contributes ``value``. + """ + + def __init__( + self, + features: tuple[str, ...], + feature: npt.NDArray[np.int64], + threshold: npt.NDArray[np.float64], + left: npt.NDArray[np.int64], + right: npt.NDArray[np.int64], + value: npt.NDArray[np.float64], + ) -> None: + """Create an ensemble from (trees, nodes) arrays.""" + self.features = features + self.feature, self.threshold, self.left, self.right, self.value = feature, threshold, left, right, value + self.depth = self._max_depth() + + @classmethod + def from_dict(cls, payload: dict) -> TreeEnsemble: + """Load the JSON format written by benchmarks/train_ranker.py.""" + trees = payload["trees"] + width = max(len(t["feature"]) for t in trees) + + def pad(key: str, fill: float, dtype: type) -> np.ndarray: + return np.array([t[key] + [fill] * (width - len(t[key])) for t in trees], dtype=dtype) + + return cls( + tuple(payload["features"]), + pad("feature", -1, np.int64), + pad("threshold", 0.0, np.float64), + pad("left", 0, np.int64), + pad("right", 0, np.int64), + pad("value", 0.0, np.float64), + ) + + def _max_depth(self) -> int: + """Longest root-to-leaf path over all trees (the number of steps predict needs).""" + deepest = 0 + for t in range(len(self.feature)): + stack = [(0, 0)] + while stack: + node, depth = stack.pop() + if self.feature[t, node] < 0: + deepest = max(deepest, depth) + else: + stack.extend(((int(self.left[t, node]), depth + 1), (int(self.right[t, node]), depth + 1))) + return deepest + + def predict(self, x: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]: + """Return the summed tree output for each row of x.""" + if not len(x): + return np.zeros(0) + n_trees = len(self.feature) + trees = np.broadcast_to(np.arange(n_trees), (len(x), n_trees)) + rows = np.broadcast_to(np.arange(len(x))[:, None], (len(x), n_trees)) + node = np.zeros((len(x), n_trees), dtype=np.int64) + for _ in range(self.depth): + feature = self.feature[trees, node] + internal = feature >= 0 + go_left = x[rows, np.maximum(feature, 0)] <= self.threshold[trees, node] + child = np.where(go_left, self.left[trees, node], self.right[trees, node]) + node = np.where(internal, child, node) + return self.value[trees, node].sum(axis=1) + + +@functools.cache +def load_ranker() -> TreeEnsemble | None: + """Return the packaged ranker, or None when disabled (SEMBLE_LEARNED_RANKER=0) or not shipped.""" + if os.environ.get("SEMBLE_LEARNED_RANKER", "1") == "0": + return None + resource = resources.files("semble.ranking").joinpath("ranker.json") + if not resource.is_file(): + return None + ensemble = TreeEnsemble.from_dict(json.loads(resource.read_text())) + if ensemble.features != FEATURES: + raise ValueError("ranker.json was trained on a different feature set; retrain it.") + return ensemble + + +def apply_learned_ranker(signals: RankingSignals, ranker: TreeEnsemble) -> dict[Chunk, float]: + """Scale each candidate's boosted score by exp(model correction).""" + chunks, x = ranking_features(signals) + correction = ranker.predict(x) + return {chunk: signals.boosted[chunk] * float(np.exp(c)) for chunk, c in zip(chunks, correction)} diff --git a/src/semble/ranking/ranker.json b/src/semble/ranking/ranker.json new file mode 100644 index 00000000..c29e2063 --- /dev/null +++ b/src/semble/ranking/ranker.json @@ -0,0 +1 @@ +{"features":["final_rank","final_rel","fused_rank","fused_rel","file_boost_rel","stem_boost_rel","definition_boost_rel","path_penalty","is_penalised_path","semantic_rank","semantic_score","semantic_rel","in_semantic","bm25_rank","bm25_rel","in_bm25","in_both","file_chunks_in_pool","file_best_final_rank","is_file_best","path_depth"],"params":{"objective":"lambdarank","n_estimators":150,"learning_rate":0.03,"num_leaves":7,"min_child_samples":200,"reg_lambda":10.0,"lambdarank_truncation_level":10,"deterministic":true,"force_row_wise":true},"trees":[{"feature":[1,4,19,-1,-1,0,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.03468772229464541,1.0000000180025095e-35,0.0,0.0,10.500000000000002,0.0,0.0,1.5000000000000002,0.0,0.016560166733665903,0.0,0.0],"left":[1,2,3,0,0,6,0,0,9,0,11,0,0],"right":[8,5,4,0,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,0.0,-0.04492447554556151,-0.028007249186095977,0.0,0.012164288106200492,-0.018884715084900548,0.0,0.04018003433864597,0.0,-0.03385556618218649,0.026028703259653542]},{"feature":[1,4,19,-1,-1,0,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.03468772229464541,1.0000000180025095e-35,0.0,0.0,10.500000000000002,0.0,0.0,1.5000000000000002,0.0,0.031046638148857632,0.0,0.0],"left":[1,2,3,0,0,6,0,0,9,0,11,0,0],"right":[8,5,4,0,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,0.0,-0.04353612500351909,-0.027466746624667564,0.0,0.01179732689142329,-0.01802843109022983,0.0,0.03938763651956324,0.0,-0.019710630538148432,0.02616464266572568]},{"feature":[1,4,19,-1,-1,0,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.032832595640316924,1.0000000180025095e-35,0.0,0.0,10.500000000000002,0.0,0.0,1.5000000000000002,0.0,0.03375380449015775,0.0,0.0],"left":[1,2,3,0,0,6,0,0,9,0,11,0,0],"right":[8,5,4,0,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,0.0,-0.04243264676754311,-0.027094600969749173,0.0,0.011189194252879018,-0.01682878459688006,0.0,0.03860296569155095,0.0,-0.011992920194782167,0.025197407999603162]},{"feature":[1,4,19,-1,-1,0,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.03192027906028078,1.0000000180025095e-35,0.0,0.0,13.500000000000002,0.0,0.0,1.5000000000000002,0.0,0.03375380449015775,0.0,0.0],"left":[1,2,3,0,0,6,0,0,9,0,11,0,0],"right":[8,5,4,0,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,0.0,-0.041481020531263256,-0.026548599629643354,0.0,0.009358369228973835,-0.02142902376652938,0.0,0.03789158503881462,0.0,-0.009974878332972292,0.024413054141368278]},{"feature":[1,4,19,-1,-1,17,-1,-1,0,-1,4,-1,-1],"threshold":[0.8561856651945636,0.032832595640316924,1.0000000180025095e-35,0.0,0.0,5.500000000000001,0.0,0.0,2.5000000000000004,0.0,0.05988322982324482,0.0,0.0],"left":[1,2,3,0,0,6,0,0,9,0,11,0,0],"right":[8,5,4,0,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,0.0,-0.04054913370054806,-0.026021337999469516,0.0,-0.01180176667138148,0.012208327021595652,0.0,0.03513175095284817,0.0,-0.019255543145680374,0.015111603752733172]},{"feature":[1,4,19,-1,-1,17,-1,-1,0,-1,4,-1,-1],"threshold":[0.8561856651945636,0.03192027906028078,1.0000000180025095e-35,0.0,0.0,5.500000000000001,0.0,0.0,1.5000000000000002,0.0,0.016560166733665903,0.0,0.0],"left":[1,2,3,0,0,6,0,0,9,0,11,0,0],"right":[8,5,4,0,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,0.0,-0.03985664382271592,-0.025759148940989483,0.0,-0.011480167449682504,0.011920492775743466,0.0,0.03650028405887545,0.0,-0.026807894629420088,0.023578859723688735]},{"feature":[1,4,19,-1,-1,17,-1,-1,0,-1,4,-1,-1],"threshold":[0.8561856651945636,0.03192027906028078,1.0000000180025095e-35,0.0,0.0,5.500000000000001,0.0,0.0,1.5000000000000002,0.0,0.02018153895125774,0.0,0.0],"left":[1,2,3,0,0,6,0,0,9,0,11,0,0],"right":[8,5,4,0,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,0.0,-0.03921510425506635,-0.025164673885515413,0.0,-0.011024955898611348,0.01125902695151539,0.0,0.03594902194974681,0.0,-0.023788569600800412,0.022952821526768124]},{"feature":[1,4,19,-1,-1,1,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.032832595640316924,1.0000000180025095e-35,0.0,0.0,0.7400519048390802,0.0,0.0,1.5000000000000002,0.0,0.04310643554837186,0.0,0.0],"left":[1,2,3,0,0,6,0,0,9,0,11,0,0],"right":[8,5,4,0,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,0.0,-0.038717246477432986,-0.024298388977408557,0.0,-0.006129128204740376,0.015082075797521063,0.0,0.035445325580138125,0.0,-0.004707747955495196,0.022843664448330466]},{"feature":[1,4,19,-1,-1,0,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.03192027906028078,1.0000000180025095e-35,0.0,0.0,13.500000000000002,0.0,0.0,1.5000000000000002,0.0,0.04310643554837186,0.0,0.0],"left":[1,2,3,0,0,6,0,0,9,0,11,0,0],"right":[8,5,4,0,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,0.0,-0.03817664021094845,-0.023833399041476095,0.0,0.008165050375586359,-0.017727103783628014,0.0,0.0349856909474364,0.0,-0.004518368680210941,0.022323846832873216]},{"feature":[1,4,19,-1,18,-1,-1,17,-1,-1,0,-1,-1],"threshold":[0.8561856651945636,0.03192027906028078,1.0000000180025095e-35,0.0,10.500000000000002,0.0,0.0,5.500000000000001,0.0,0.0,2.5000000000000004,0.0,0.0],"left":[1,2,3,0,5,0,0,8,0,0,11,0,0],"right":[10,7,4,0,6,0,0,9,0,0,12,0,0],"value":[0.0,0.0,0.0,-0.03762567343312929,0.0,-0.0010031587026929055,-0.02773565462864988,0.0,-0.011027444666685132,0.010557119083700394,0.0,0.03258376532533569,0.0023911131576352775]},{"feature":[1,4,19,-1,-1,5,17,-1,-1,-1,0,-1,-1],"threshold":[0.8755395009167027,0.03192027906028078,1.0000000180025095e-35,0.0,0.0,1.0000000180025095e-35,5.500000000000001,0.0,0.0,0.0,1.5000000000000002,0.0,0.0],"left":[1,2,3,0,0,6,7,0,0,0,11,0,0],"right":[10,5,4,0,0,9,8,0,0,0,12,0,0],"value":[0.0,0.0,0.0,-0.03726004960435375,-0.022791244725636223,0.0,0.0,-0.024592050353968976,0.0010648300785221691,0.015591323905361417,0.0,0.03408081762619563,0.01640863512571287]},{"feature":[1,4,19,-1,-1,5,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.03192027906028078,1.0000000180025095e-35,0.0,0.0,1.0000000180025095e-35,0.0,0.0,1.5000000000000002,0.0,0.04310643554837186,0.0,0.0],"left":[1,2,3,0,0,6,0,0,9,0,11,0,0],"right":[8,5,4,0,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,0.0,-0.036836345085903374,-0.022389566469201795,0.0,-0.008943294926779574,0.014750021307103733,0.0,0.033735957971169,0.0,-0.00572822888037629,0.021293915554122727]},{"feature":[1,4,19,-1,-1,5,17,-1,-1,-1,0,-1,-1],"threshold":[0.8755395009167027,0.03192027906028078,1.0000000180025095e-35,0.0,0.0,1.0000000180025095e-35,5.500000000000001,0.0,0.0,0.0,1.5000000000000002,0.0,0.0],"left":[1,2,3,0,0,6,7,0,0,0,11,0,0],"right":[10,5,4,0,0,9,8,0,0,0,12,0,0],"value":[0.0,0.0,0.0,-0.036481805509045354,-0.021895495607358477,0.0,0.0,-0.023249618203478768,0.001487214368100314,0.013779034364015312,0.0,0.03339463700500388,0.015817840831798758]},{"feature":[1,4,19,-1,-1,5,17,-1,-1,-1,0,-1,-1],"threshold":[0.8755395009167027,0.03192027906028078,1.0000000180025095e-35,0.0,0.0,1.0000000180025095e-35,5.500000000000001,0.0,0.0,0.0,1.5000000000000002,0.0,0.0],"left":[1,2,3,0,0,6,7,0,0,0,11,0,0],"right":[10,5,4,0,0,9,8,0,0,0,12,0,0],"value":[0.0,0.0,0.0,-0.036142561801415896,-0.021380173219092965,0.0,0.0,-0.02288130256612565,0.0018436808269280177,0.013017693835421765,0.0,0.03308908765170128,0.015309443937743744]},{"feature":[1,4,19,-1,-1,5,-1,-1,0,-1,4,-1,-1],"threshold":[0.8561856651945636,0.03192027906028078,1.0000000180025095e-35,0.0,0.0,1.0000000180025095e-35,0.0,0.0,1.5000000000000002,0.0,0.016560166733665903,0.0,0.0],"left":[1,2,3,0,0,6,0,0,9,0,11,0,0],"right":[8,5,4,0,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,0.0,-0.03573067855544868,-0.021207136973797093,0.0,-0.00807796937727574,0.011513838655851972,0.0,0.032789560268935716,0.0,-0.02245239164122061,0.019626303084036355]},{"feature":[0,1,4,-1,-1,-1,4,-1,0,5,-1,-1,-1],"threshold":[2.5000000000000004,0.9408753422697916,0.046252661058910946,0.0,0.0,0.0,0.01323682629006251,0.0,13.500000000000002,1.0000000180025095e-35,0.0,0.0,0.0],"left":[1,2,3,0,0,0,7,0,9,10,0,0,0],"right":[6,5,4,0,0,0,8,0,12,11,0,0,0],"value":[0.0,0.0,0.0,-0.01805826665009784,0.01844444840872358,0.0317188234296743,0.0,-0.034115823368296626,0.0,0.0,-0.002563066032839915,0.012008335767909448,-0.019122620180954054]},{"feature":[1,4,-1,0,17,-1,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.01323682629006251,0.0,13.500000000000002,3.5000000000000004,0.0,0.0,0.0,1.5000000000000002,0.0,0.04310643554837186,0.0,0.0],"left":[1,2,0,4,5,0,0,0,9,0,11,0,0],"right":[8,3,0,7,6,0,0,0,10,0,12,0,0],"value":[0.0,0.0,-0.03401505431440204,0.0,0.0,-0.006330643832109109,0.01003893204591252,-0.018686345665949903,0.0,0.03210645809723371,0.0,-0.004242038892446607,0.019295526914159106]},{"feature":[1,4,-1,0,5,-1,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.01323682629006251,0.0,13.500000000000002,1.0000000180025095e-35,0.0,0.0,0.0,1.5000000000000002,0.0,0.04310643554837186,0.0,0.0],"left":[1,2,0,4,5,0,0,0,9,0,11,0,0],"right":[8,3,0,7,6,0,0,0,10,0,12,0,0],"value":[0.0,0.0,-0.033727932866319255,0.0,0.0,-0.0028774408333749396,0.011791812451188585,-0.018263135103668494,0.0,0.03182912818196495,0.0,-0.004349730378858986,0.018870972478638913]},{"feature":[0,1,4,-1,-1,-1,4,-1,0,5,-1,-1,-1],"threshold":[2.5000000000000004,0.9408753422697916,0.046252661058910946,0.0,0.0,0.0,0.01323682629006251,0.0,13.500000000000002,1.0000000180025095e-35,0.0,0.0,0.0],"left":[1,2,3,0,0,0,7,0,9,10,0,0,0],"right":[6,5,4,0,0,0,8,0,12,11,0,0,0],"value":[0.0,0.0,0.0,-0.016074190267084,0.01724441016944274,0.030789393823079613,0.0,-0.03323727749831113,0.0,0.0,-0.0032051353997605316,0.01075137218280135,-0.017597728599368964]},{"feature":[1,4,-1,0,17,-1,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.01323682629006251,0.0,13.500000000000002,3.5000000000000004,0.0,0.0,0.0,1.5000000000000002,0.0,0.04310643554837186,0.0,0.0],"left":[1,2,0,4,5,0,0,0,9,0,11,0,0],"right":[8,3,0,7,6,0,0,0,10,0,12,0,0],"value":[0.0,0.0,-0.03320018050953494,0.0,0.0,-0.006743597470550113,0.008769451503593446,-0.01728943415971968,0.0,0.031239059711355148,0.0,-0.003734542621023587,0.018213700751217927]},{"feature":[1,4,-1,0,5,-1,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.01323682629006251,0.0,13.500000000000002,1.0000000180025095e-35,0.0,0.0,0.0,1.5000000000000002,0.0,0.04310643554837186,0.0,0.0],"left":[1,2,0,4,5,0,0,0,9,0,11,0,0],"right":[8,3,0,7,6,0,0,0,10,0,12,0,0],"value":[0.0,0.0,-0.032962634473571985,0.0,0.0,-0.0035004811157681188,0.010493175019356678,-0.016740705944925795,0.0,0.030997595179842265,0.0,-0.0037291448741003674,0.017808507735427883]},{"feature":[0,1,4,-1,-1,-1,4,-1,0,14,-1,-1,-1],"threshold":[2.5000000000000004,0.9408753422697916,0.046252661058910946,0.0,0.0,0.0,0.01323682629006251,0.0,13.500000000000002,0.6989431304514542,0.0,0.0,0.0],"left":[1,2,3,0,0,0,7,0,9,10,0,0,0],"right":[6,5,4,0,0,0,8,0,12,11,0,0,0],"value":[0.0,0.0,0.0,-0.015273936685705022,0.016133585659853365,0.02995005247962787,0.0,-0.03248998653124667,0.0,0.0,-0.0031171489210861463,0.010303441437009361,-0.0163528914180614]},{"feature":[1,4,-1,17,-1,5,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.01323682629006251,0.0,3.5000000000000004,0.0,1.0000000180025095e-35,0.0,0.0,1.5000000000000002,0.0,0.04310643554837186,0.0,0.0],"left":[1,2,0,4,0,6,0,0,9,0,11,0,0],"right":[8,3,0,5,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,-0.03253144378257428,0.0,-0.014364053060667977,0.0,-0.0036515696945109383,0.01434098292243752,0.0,0.030478169031943423,0.0,-0.003454789400973249,0.017188149883338305]},{"feature":[1,4,-1,17,-1,5,-1,-1,0,-1,4,-1,-1],"threshold":[0.8755395009167027,0.01323682629006251,0.0,3.5000000000000004,0.0,1.0000000180025095e-35,0.0,0.0,1.5000000000000002,0.0,0.03468772229464541,0.0,0.0],"left":[1,2,0,4,0,6,0,0,9,0,11,0,0],"right":[8,3,0,5,0,7,0,0,10,0,12,0,0],"value":[0.0,0.0,-0.03230695504740302,0.0,-0.014070459421979375,0.0,-0.0035350574502449857,0.013784590605943,0.0,0.03024180728108247,0.0,-0.004520182526642539,0.016579884222437648]},{"feature":[0,1,4,-1,-1,-1,4,-1,4,5,-1,-1,-1],"threshold":[2.5000000000000004,0.9408753422697916,0.046252661058910946,0.0,0.0,0.0,0.01323682629006251,0.0,0.09068361409973183,0.13207623446444114,0.0,0.0,0.0],"left":[1,2,3,0,0,0,7,0,9,10,0,0,0],"right":[6,5,4,0,0,0,8,0,12,11,0,0,0],"value":[0.0,0.0,0.0,-0.015124951069761016,0.015162233467344658,0.029172981188512758,0.0,-0.03185472502548297,0.0,0.0,-0.016155988189939956,0.0006760479960213274,0.009716507822196449]},{"feature":[1,4,-1,17,5,-1,-1,-1,0,-1,4,-1,-1],"threshold":[0.8561856651945636,0.01323682629006251,0.0,5.500000000000001,0.13207623446444114,0.0,0.0,0.0,1.5000000000000002,0.0,0.020440492480203975,0.0,0.0],"left":[1,2,0,4,5,0,0,0,9,0,11,0,0],"right":[8,3,0,7,6,0,0,0,10,0,12,0,0],"value":[0.0,0.0,-0.031850337317644604,0.0,0.0,-0.01891147359772132,-0.000626783692136602,0.00639085015638549,0.0,0.029741462245959898,0.0,-0.01686127801980597,0.016132512824177787]},{"feature":[1,4,-1,17,1,-1,14,-1,-1,-1,0,-1,-1],"threshold":[0.8755395009167027,0.01323682629006251,0.0,5.500000000000001,0.4833148335307725,0.0,0.7661940073326431,0.0,0.0,0.0,1.5000000000000002,0.0,0.0],"left":[1,2,0,4,5,0,7,0,0,0,11,0,0],"right":[10,3,0,9,6,0,8,0,0,0,12,0,0],"value":[0.0,0.0,-0.031751892836179324,0.0,0.0,-0.021942049064756983,0.0,-0.008610497738546337,0.00907473747278994,0.0069688873516726485,0.0,0.029514952948301088,0.01220481465208504]},{"feature":[1,4,-1,17,5,-1,-1,-1,0,-1,4,-1,-1],"threshold":[0.8561856651945636,0.01323682629006251,0.0,5.500000000000001,0.13207623446444114,0.0,0.0,0.0,1.5000000000000002,0.0,0.02018153895125774,0.0,0.0],"left":[1,2,0,4,5,0,0,0,9,0,11,0,0],"right":[8,3,0,7,6,0,0,0,10,0,12,0,0],"value":[0.0,0.0,-0.031502235903438744,0.0,0.0,-0.018338307269940395,-0.0006703757738499583,0.006072244962319056,0.0,0.029319881001398526,0.0,-0.016364841791157308,0.01549862473351133]},{"feature":[0,1,-1,-1,19,-1,0,7,-1,5,-1,-1,-1],"threshold":[2.5000000000000004,0.9408753422697916,0.0,0.0,1.0000000180025095e-35,0.0,29.500000000000004,0.7500000000000001,0.0,0.12933324930428017,0.0,0.0,0.0],"left":[1,2,0,0,5,0,7,8,0,10,0,0,0],"right":[4,3,0,0,6,0,12,9,0,11,0,0,0],"value":[0.0,0.0,0.00710366621271699,0.028219688703870448,0.0,-0.03321663582048999,0.0,0.0,-0.029486340631043082,0.0,-0.004845924139381521,0.010146953055851919,-0.022866220421651505]},{"feature":[1,19,-1,0,4,-1,-1,-1,0,-1,4,-1,-1],"threshold":[0.8561856651945636,1.0000000180025095e-35,0.0,29.500000000000004,0.09068361409973183,0.0,0.0,0.0,1.5000000000000002,0.0,0.020440492480203975,0.0,0.0],"left":[1,2,0,4,5,0,0,0,9,0,11,0,0],"right":[8,3,0,7,6,0,0,0,10,0,12,0,0],"value":[0.0,0.0,-0.03298563576961305,0.0,0.0,-0.0051395582495915295,0.010613527661010242,-0.022645488761356074,0.0,0.028853467077136655,0.0,-0.015501487052484981,0.01500382080800481]},{"feature":[0,1,-1,-1,19,-1,0,5,11,-1,-1,-1,-1],"threshold":[2.5000000000000004,0.9408753422697916,0.0,0.0,1.0000000180025095e-35,0.0,29.500000000000004,0.12933324930428017,0.9029070776056402,0.0,0.0,0.0,0.0],"left":[1,2,0,0,5,0,7,8,9,0,0,0,0],"right":[4,3,0,0,6,0,12,11,10,0,0,0,0],"value":[0.0,0.0,0.0070659823428289685,0.0277272231036592,0.0,-0.032984143016687506,0.0,0.0,0.0,-0.011845254731930408,0.00797769413020605,0.008012112110309963,-0.022340560982065077]},{"feature":[1,19,-1,0,5,-1,-1,-1,0,-1,4,-1,-1],"threshold":[0.8416864984174791,1.0000000180025095e-35,0.0,29.500000000000004,1.0000000180025095e-35,0.0,0.0,0.0,1.5000000000000002,0.0,0.005231972967520287,0.0,0.0],"left":[1,2,0,4,5,0,0,0,9,0,11,0,0],"right":[8,3,0,7,6,0,0,0,10,0,12,0,0],"value":[0.0,0.0,-0.032813086783159244,0.0,0.0,-0.007715769125064834,0.006921532675080758,-0.022078888941882865,0.0,0.02839763952169366,0.0,-0.019744019148267816,0.014389561926259785]},{"feature":[1,19,-1,0,4,5,-1,-1,-1,-1,0,-1,-1],"threshold":[0.8755395009167027,1.0000000180025095e-35,0.0,29.500000000000004,0.09068361409973183,1.0000000180025095e-35,0.0,0.0,0.0,0.0,1.5000000000000002,0.0,0.0],"left":[1,2,0,4,5,6,0,0,0,0,11,0,0],"right":[10,3,0,9,8,7,0,0,0,0,12,0,0],"value":[0.0,0.0,-0.03268912848553982,0.0,0.0,0.0,-0.011596968734067355,0.001899442849828457,0.010749713551297639,-0.02181626760783313,0.0,0.02819051708195876,0.01110184447694563]},{"feature":[0,1,-1,-1,19,-1,0,7,-1,5,-1,-1,-1],"threshold":[2.5000000000000004,0.9408753422697916,0.0,0.0,1.0000000180025095e-35,0.0,29.500000000000004,0.7500000000000001,0.0,0.12933324930428017,0.0,0.0,0.0],"left":[1,2,0,0,5,0,7,8,0,10,0,0,0],"right":[4,3,0,0,6,0,12,9,0,11,0,0,0],"value":[0.0,0.0,0.006435949589654937,0.02706315895958138,0.0,-0.03259673495764682,0.0,0.0,-0.028194234537482418,0.0,-0.004615083878020352,0.009065009207527161,-0.021516485455972692]},{"feature":[1,19,-1,0,4,5,-1,-1,-1,-1,0,-1,-1],"threshold":[0.8755395009167027,1.0000000180025095e-35,0.0,29.500000000000004,0.09068361409973183,1.0000000180025095e-35,0.0,0.0,0.0,0.0,1.5000000000000002,0.0,0.0],"left":[1,2,0,4,5,6,0,0,0,0,11,0,0],"right":[10,3,0,9,8,7,0,0,0,0,12,0,0],"value":[0.0,0.0,-0.03243573948629559,0.0,0.0,0.0,-0.011273085998896917,0.0014787590950006142,0.01026594727212848,-0.021199097006164028,0.0,0.027737006820037373,0.010851167005322923]},{"feature":[1,19,-1,17,5,-1,-1,14,-1,-1,0,-1,-1],"threshold":[0.8755395009167027,1.0000000180025095e-35,0.0,3.5000000000000004,1.0000000180025095e-35,0.0,0.0,0.6002506753056506,0.0,0.0,1.5000000000000002,0.0,0.0],"left":[1,2,0,4,5,0,0,8,0,0,11,0,0],"right":[10,3,0,7,6,0,0,9,0,0,12,0,0],"value":[0.0,0.0,-0.03230832084606906,0.0,0.0,-0.019531092644264367,-0.00440650144985819,0.0,-0.004766946449608763,0.010807052030570204,0.0,0.027535382275039474,0.010597935164455959]},{"feature":[0,1,-1,-1,19,-1,0,7,-1,5,-1,-1,-1],"threshold":[2.5000000000000004,0.9408753422697916,0.0,0.0,1.0000000180025095e-35,0.0,29.500000000000004,0.7500000000000001,0.0,0.12933324930428017,0.0,0.0,0.0],"left":[1,2,0,0,5,0,7,8,0,10,0,0,0],"right":[4,3,0,0,6,0,12,9,0,11,0,0,0],"value":[0.0,0.0,0.00654503592233602,0.02634507677764579,0.0,-0.032256393187505075,0.0,0.0,-0.02754931994683281,0.0,-0.004488636498414438,0.008389897400200288,-0.020600992116394032]},{"feature":[1,19,-1,0,13,-1,-1,-1,0,-1,4,-1,-1],"threshold":[0.8416864984174791,1.0000000180025095e-35,0.0,29.500000000000004,8.500000000000002,0.0,0.0,0.0,1.5000000000000002,0.0,0.005231972967520287,0.0,0.0],"left":[1,2,0,4,5,0,0,0,9,0,11,0,0],"right":[8,3,0,7,6,0,0,0,10,0,12,0,0],"value":[0.0,0.0,-0.03214350577476076,0.0,0.0,0.008677244008381007,-0.005662660047915036,-0.020261625808458913,0.0,0.027065687196928062,0.0,-0.018754705432620585,0.013261357354563899]},{"feature":[19,-1,0,-1,0,7,-1,4,3,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,2.5000000000000004,0.0,29.500000000000004,0.7500000000000001,0.0,0.09068361409973183,0.5873023616282739,0.0,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,8,9,0,0,0,0],"right":[2,0,4,0,12,7,0,11,10,0,0,0,0],"value":[0.0,-0.032284880351506264,0.0,0.02446674557436055,0.0,0.0,-0.026733625208657255,0.0,0.0,0.007106550198477,-0.00660357235835677,0.01072704503680277,-0.01991048364995174]},{"feature":[19,-1,0,-1,0,14,13,-1,-1,-1,5,-1,-1],"threshold":[1.0000000180025095e-35,0.0,2.5000000000000004,0.0,13.500000000000002,0.6934095264287193,35.50000000000001,0.0,0.0,0.0,0.39827646307193504,0.0,0.0],"left":[1,0,3,0,5,6,7,0,0,0,11,0,0],"right":[2,0,4,0,10,9,8,0,0,0,12,0,0],"value":[0.0,-0.03215029824706265,0.0,0.02406201924556551,0.0,0.0,0.0,-0.009003411128701257,0.009678169163700874,0.009161314673114405,0.0,-0.01566428451760005,0.010143637520289538]},{"feature":[19,-1,0,1,-1,-1,0,17,-1,-1,5,-1,-1],"threshold":[1.0000000180025095e-35,0.0,2.5000000000000004,0.9408753422697916,0.0,0.0,13.500000000000002,7.500000000000001,0.0,0.0,0.39827646307193504,0.0,0.0],"left":[1,0,3,4,0,0,7,8,0,0,11,0,0],"right":[2,0,6,5,0,0,10,9,0,0,12,0,0],"value":[0.0,-0.03208307298267252,0.0,0.0,0.009893977436869312,0.02547488324074457,0.0,0.0,-0.001637013688579297,0.010221972825589403,0.0,-0.015308860622937404,0.009927723113739486]},{"feature":[19,-1,0,-1,0,7,-1,5,11,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,2.5000000000000004,0.0,29.500000000000004,0.7500000000000001,0.0,0.12933324930428017,0.9029070776056402,0.0,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,8,9,0,0,0,0],"right":[2,0,4,0,12,7,0,11,10,0,0,0,0],"value":[0.0,-0.03198691729313056,0.0,0.023362880530656403,0.0,0.0,-0.025942819795512256,0.0,0.0,-0.009030202877065817,0.008488646120894698,0.008212008953515086,-0.018999936886050138]},{"feature":[19,-1,0,-1,5,9,-1,17,-1,-1,17,-1,-1],"threshold":[1.0000000180025095e-35,0.0,2.5000000000000004,0.0,0.12933324930428017,3.5000000000000004,0.0,6.500000000000001,0.0,0.0,7.500000000000001,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,0,11,0,0],"right":[2,0,4,0,10,7,0,9,0,0,12,0,0],"value":[0.0,-0.03192367878182879,0.0,0.022973107933742853,0.0,0.0,0.006849687723515902,0.0,-0.018861058216418914,-0.0014846234183721638,0.0,0.00041658087066602544,0.01658686311875245]},{"feature":[19,-1,0,1,-1,-1,5,13,-1,-1,4,-1,-1],"threshold":[1.0000000180025095e-35,0.0,2.5000000000000004,0.9408753422697916,0.0,0.0,0.12933324930428017,6.500000000000001,0.0,0.0,0.09068361409973183,0.0,0.0],"left":[1,0,3,4,0,0,7,8,0,0,11,0,0],"right":[2,0,6,5,0,0,10,9,0,0,12,0,0],"value":[0.0,-0.03188840483534644,0.0,0.0,0.008492533718312975,0.024550722678419203,0.0,0.0,0.004256677364409024,-0.014556777400249125,0.0,0.00012476394880064557,0.015756647650101065]},{"feature":[19,-1,1,17,5,11,-1,-1,-1,-1,1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.820659135683696,7.500000000000001,0.13207623446444114,0.9333712129279735,0.0,0.0,0.0,0.0,0.9998615875408933,0.0,0.0],"left":[1,0,3,4,5,6,0,0,0,0,11,0,0],"right":[2,0,10,9,8,7,0,0,0,0,12,0,0],"value":[0.0,-0.031761244149993546,0.0,0.0,0.0,0.0,-0.019078554785421333,0.004469931879780221,-0.0006984011188901453,0.008616623742405132,0.0,0.011298825607959957,0.02506013329782458]},{"feature":[19,-1,1,17,5,11,-1,-1,-1,-1,1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.820659135683696,7.500000000000001,0.13207623446444114,0.9333712129279735,0.0,0.0,0.0,0.0,0.9998615875408933,0.0,0.0],"left":[1,0,3,4,5,6,0,0,0,0,11,0,0],"right":[2,0,10,9,8,7,0,0,0,0,12,0,0],"value":[0.0,-0.031660169297682,0.0,0.0,0.0,0.0,-0.01878730316307897,0.004439512796538024,-0.0004973726950331502,0.008269856100794662,0.0,0.011037568007458264,0.02481266768166763]},{"feature":[19,-1,0,1,-1,-1,4,1,-1,3,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,2.5000000000000004,0.9408753422697916,0.0,0.0,0.09068361409973183,0.40226698048681436,0.0,0.5779636833968026,0.0,0.0,0.0],"left":[1,0,3,4,0,0,7,8,0,10,0,0,0],"right":[2,0,6,5,0,0,12,9,0,11,0,0,0],"value":[0.0,-0.0315930469690667,0.0,0.0,0.00785598368678055,0.02373838367770248,0.0,0.0,-0.01778350105758648,0.0,0.006096886163950554,-0.006543551688142284,0.008469094794800002]},{"feature":[19,-1,1,5,13,-1,-1,14,-1,-1,1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.820659135683696,1.0000000180025095e-35,5.500000000000001,0.0,0.0,0.6002506753056506,0.0,0.0,0.9998615875408933,0.0,0.0],"left":[1,0,3,4,5,0,0,8,0,0,11,0,0],"right":[2,0,10,7,6,0,0,9,0,0,12,0,0],"value":[0.0,-0.03148377164725196,0.0,0.0,0.0,0.0038458697807691594,-0.014993731323552324,0.0,-0.003242410575615863,0.010771441119488597,0.0,0.010735972423090566,0.0242436191643802]},{"feature":[19,-1,1,5,17,-1,-1,4,-1,-1,1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.820659135683696,1.0000000180025095e-35,6.500000000000001,0.0,0.0,0.08808437110797789,0.0,0.0,0.9998615875408933,0.0,0.0],"left":[1,0,3,4,5,0,0,8,0,0,11,0,0],"right":[2,0,10,7,6,0,0,9,0,0,12,0,0],"value":[0.0,-0.031414820995266046,0.0,0.0,0.0,-0.015904764040274855,0.0007722104215675329,0.0,-0.0009062351977323573,0.015154201765074054,0.0,0.010468873958702048,0.023966101085509815]},{"feature":[19,-1,1,14,17,5,-1,-1,-1,-1,1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7848368634117361,0.7661940073326431,7.500000000000001,0.13207623446444114,0.0,0.0,0.0,0.0,0.9998615875408933,0.0,0.0],"left":[1,0,3,4,5,6,0,0,0,0,11,0,0],"right":[2,0,10,9,8,7,0,0,0,0,12,0,0],"value":[0.0,-0.0313235678394064,0.0,0.0,0.0,0.0,-0.018438024143673484,-0.004676038071255543,0.003144889288071654,0.007507183253621761,0.0,0.0098534372723283,0.02370002658335794]},{"feature":[19,-1,1,14,5,11,-1,-1,-1,4,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9408753422697916,0.6002506753056506,0.17119099965370907,0.899600070411435,0.0,0.0,0.0,0.09068361409973183,0.0,0.0,0.0],"left":[1,0,3,4,5,6,0,0,0,10,0,0,0],"right":[2,0,12,9,8,7,0,0,0,11,0,0,0],"value":[0.0,-0.03129813182484941,0.0,0.0,0.0,0.0,-0.018346120548003313,0.0033572702915742694,-0.0007223629951162594,0.0,-0.00031220819654980894,0.01397451183803567,0.022118485488687334]},{"feature":[19,-1,1,5,17,-1,-1,17,-1,-1,1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.820659135683696,1.0000000180025095e-35,6.500000000000001,0.0,0.0,1.5000000000000002,0.0,0.0,0.9998615875408933,0.0,0.0],"left":[1,0,3,4,5,0,0,8,0,0,11,0,0],"right":[2,0,10,7,6,0,0,9,0,0,12,0,0],"value":[0.0,-0.031248072169344394,0.0,0.0,0.0,-0.014973267895238408,0.0008981658598565121,0.0,-0.007719084253724513,0.0073042296979367915,0.0,0.01008073138494923,0.023094110151768515]},{"feature":[19,-1,0,1,-1,-1,5,9,-1,-1,7,-1,-1],"threshold":[1.0000000180025095e-35,0.0,2.5000000000000004,0.9408753422697916,0.0,0.0,0.12933324930428017,4.500000000000001,0.0,0.0,0.7500000000000001,0.0,0.0],"left":[1,0,3,4,0,0,7,8,0,0,11,0,0],"right":[2,0,6,5,0,0,10,9,0,0,12,0,0],"value":[0.0,-0.03120817967128588,0.0,0.0,0.0066161399805824165,0.02205555505420304,0.0,0.0,0.005783198515828566,-0.012225405915619101,0.0,-0.018984617044873107,0.006501314718501299]},{"feature":[19,-1,1,4,5,11,-1,-1,-1,-1,1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.8755395009167027,0.09068361409973183,1.0000000180025095e-35,0.8961575824789966,0.0,0.0,0.0,0.0,0.9998615875408933,0.0,0.0],"left":[1,0,3,4,5,6,0,0,0,0,11,0,0],"right":[2,0,10,9,8,7,0,0,0,0,12,0,0],"value":[0.0,-0.03100779256289846,0.0,0.0,0.0,0.0,-0.016499592514425385,0.004550249201382942,-0.0005015722709118538,0.009108582164127334,0.0,0.010497480579926367,0.022496338429598407]},{"feature":[19,-1,1,17,5,11,-1,-1,-1,-1,1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.820659135683696,7.500000000000001,0.13207623446444114,0.9333712129279735,0.0,0.0,0.0,0.0,0.9998615875408933,0.0,0.0],"left":[1,0,3,4,5,6,0,0,0,0,11,0,0],"right":[2,0,10,9,8,7,0,0,0,0,12,0,0],"value":[0.0,-0.03084785757260343,0.0,0.0,0.0,0.0,-0.016498944185105148,0.004364843296998963,-0.0004665540190403401,0.007734138715669165,0.0,0.009574017989813319,0.02220433156035526]},{"feature":[19,-1,1,14,5,-1,-1,7,-1,4,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9408753422697916,0.6002506753056506,0.17119099965370907,0.0,0.0,0.7500000000000001,0.0,0.09068361409973183,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,8,0,10,0,0,0],"right":[2,0,12,7,6,0,0,9,0,11,0,0,0],"value":[0.0,-0.030731288107999483,0.0,0.0,0.0,-0.013530720682872551,-0.0010899887368977532,0.0,-0.020446501399240202,0.0,0.0012119092848183715,0.014925240545854175,0.02058348944682248]},{"feature":[19,-1,1,14,5,17,-1,-1,-1,-1,1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.820659135683696,0.7661940073326431,1.0000000180025095e-35,6.500000000000001,0.0,0.0,0.0,0.0,0.9998615875408933,0.0,0.0],"left":[1,0,3,4,5,6,0,0,0,0,11,0,0],"right":[2,0,10,9,8,7,0,0,0,0,12,0,0],"value":[0.0,-0.030662150054176676,0.0,0.0,0.0,0.0,-0.017232959660308255,-0.0018021674398349663,-0.000770006880261729,0.007707194809424439,0.0,0.009266040770914634,0.021580972374724033]},{"feature":[19,-1,1,17,5,-1,-1,-1,1,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7400519048390802,7.500000000000001,0.16417518921539875,0.0,0.0,0.0,0.9998615875408933,0.5556618045961942,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,0,9,10,0,0,0],"right":[2,0,8,7,6,0,0,0,12,11,0,0,0],"value":[0.0,-0.030626850870076567,0.0,0.0,0.0,-0.014857542598456746,-0.0015105451303556558,0.006695834274751445,0.0,0.0,-0.0022645702588265505,0.010559126077712328,0.021291542150822296]},{"feature":[19,-1,1,14,5,17,-1,-1,-1,-1,1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.820659135683696,0.7661940073326431,1.0000000180025095e-35,11.500000000000002,0.0,0.0,0.0,0.0,0.9998615875408933,0.0,0.0],"left":[1,0,3,4,5,6,0,0,0,0,11,0,0],"right":[2,0,10,9,8,7,0,0,0,0,12,0,0],"value":[0.0,-0.030460728775076062,0.0,0.0,0.0,0.0,-0.015352133141300362,0.002723271560259962,-0.0006696903076124103,0.007524981396851186,0.0,0.009061112924252337,0.020975073337163783]},{"feature":[19,-1,1,14,5,-1,-1,-1,14,-1,17,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.820659135683696,0.7661940073326431,1.0000000180025095e-35,0.0,0.0,0.0,0.5556618045961942,0.0,5.500000000000001,0.0,0.0],"left":[1,0,3,4,5,0,0,0,9,0,11,0,0],"right":[2,0,8,7,6,0,0,0,10,0,12,0,0],"value":[0.0,-0.030392986856894212,0.0,0.0,0.0,-0.012784574971797243,-0.0006739855294927623,0.007476956146416393,0.0,-0.00036316896407764386,0.0,0.007951563388459842,0.020742879135729093]},{"feature":[19,-1,1,7,-1,14,5,9,-1,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9408753422697916,0.7500000000000001,0.0,0.7661940073326431,1.0000000180025095e-35,4.500000000000001,0.0,0.0,0.0,0.0,0.0],"left":[1,0,3,4,0,6,7,8,0,0,0,0,0],"right":[2,0,12,5,0,11,10,9,0,0,0,0,0],"value":[0.0,-0.03029472650107386,0.0,0.0,-0.027486757192260937,0.0,0.0,0.0,0.004131269085718704,-0.013508813448008767,0.002824645903155818,0.010400718996084204,0.01907532312439605]},{"feature":[19,-1,1,7,-1,4,5,11,-1,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9408753422697916,0.7500000000000001,0.0,0.09068361409973183,1.0000000180025095e-35,0.8961575824789966,0.0,0.0,0.0,0.0,0.0],"left":[1,0,3,4,0,6,7,8,0,0,0,0,0],"right":[2,0,12,5,0,11,10,9,0,0,0,0,0],"value":[0.0,-0.030181391112953388,0.0,0.0,-0.027362955651004696,0.0,0.0,0.0,-0.01316651448253235,0.005840532475281701,0.0018540926523175102,0.010434042822991903,0.018736505949762075]},{"feature":[19,-1,1,17,5,-1,-1,-1,3,17,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7400519048390802,7.500000000000001,0.16417518921539875,0.0,0.0,0.0,0.9839089345154072,5.500000000000001,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,0,9,10,0,0,0],"right":[2,0,8,7,6,0,0,0,12,11,0,0,0],"value":[0.0,-0.030108859232735177,0.0,0.0,0.0,-0.013908888916930174,-0.0012420518726796983,0.006716913292747325,0.0,0.0,-0.0009249050649202345,0.012518142473707397,0.020163908788715677]},{"feature":[19,-1,1,17,5,-1,-1,-1,1,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7400519048390802,7.500000000000001,0.16417518921539875,0.0,0.0,0.0,0.9998615875408933,0.9441804761364593,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,0,9,10,0,0,0],"right":[2,0,8,7,6,0,0,0,12,11,0,0,0],"value":[0.0,-0.029935307611911762,0.0,0.0,0.0,-0.013640176313941968,-0.001359402133853979,0.006503706697422683,0.0,0.0,0.004257928879952523,0.01676235465687547,0.019289754339901596]},{"feature":[19,-1,1,7,-1,4,5,11,-1,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9408753422697916,0.7500000000000001,0.0,0.09068361409973183,1.0000000180025095e-35,0.8961575824789966,0.0,0.0,0.0,0.0,0.0],"left":[1,0,3,4,0,6,7,8,0,0,0,0,0],"right":[2,0,12,5,0,11,10,9,0,0,0,0,0],"value":[0.0,-0.02982493637951769,0.0,0.0,-0.026382578531212172,0.0,0.0,0.0,-0.01290047778137527,0.0054763033022651895,0.0017275849350064,0.010086612421443136,0.017771018848235547]},{"feature":[19,-1,1,7,-1,4,5,11,-1,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9408753422697916,0.7500000000000001,0.0,0.09068361409973183,1.0000000180025095e-35,0.8961575824789966,0.0,0.0,0.0,0.0,0.0],"left":[1,0,3,4,0,6,7,8,0,0,0,0,0],"right":[2,0,12,5,0,11,10,9,0,0,0,0,0],"value":[0.0,-0.029692552845227035,0.0,0.0,-0.026128403341692162,0.0,0.0,0.0,-0.012607631993176827,0.005375131599849951,0.001623960870841296,0.009966112488701665,0.017389118092675515]},{"feature":[19,-1,4,1,17,-1,-1,-1,14,13,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.09068361409973183,0.8755395009167027,1.5000000000000002,0.0,0.0,0.0,0.5579044266708318,34.50000000000001,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,0,9,10,0,0,0],"right":[2,0,8,7,6,0,0,0,12,11,0,0,0],"value":[0.0,-0.029587968383015296,0.0,0.0,0.0,-0.013698922672573274,-0.0016976559778622605,0.0077915575747637645,0.0,0.0,-0.010244940041119269,0.009138311265560604,0.017418730105698256]},{"feature":[19,-1,7,-1,4,1,-1,4,-1,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.09068361409973183,0.40226698048681436,0.0,0.006000603115980676,0.0,0.0,0.5579044266708318,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,0,11,0,0],"right":[2,0,4,0,10,7,0,9,0,0,12,0,0],"value":[0.0,-0.02946732140605,0.0,-0.033229033056797426,0.0,0.0,-0.01182741062198983,0.0,0.01630555873231596,0.00023182121000041569,0.0,-0.00039110707131501934,0.01853177838442656]},{"feature":[19,-1,7,-1,0,14,-1,-1,17,-1,5,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,2.5000000000000004,0.5833938301109745,0.0,0.0,1.5000000000000002,0.0,0.12933324930428017,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,0,11,0,0],"right":[2,0,4,0,8,7,0,0,10,0,12,0,0],"value":[0.0,-0.029399879369252462,0.0,-0.032746784373892106,0.0,0.0,0.001207788581265667,0.018377783481804678,0.0,-0.010254437644272111,0.0,-0.0026146553442204534,0.008578428954759711]},{"feature":[19,-1,7,-1,1,-1,14,-1,17,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.7400519048390802,0.0,0.5556618045961942,0.0,5.500000000000001,0.9441804761364593,0.0,0.0,0.0],"left":[1,0,3,0,5,0,7,0,9,10,0,0,0],"right":[2,0,4,0,6,0,8,0,12,11,0,0,0],"value":[0.0,-0.02937371930620901,0.0,-0.03282153782876457,0.0,-0.003110734353290789,0.0,-0.0002243177406385568,0.0,0.0,-0.00030258856138170535,0.016622058740224547,0.018882792139975683]},{"feature":[19,-1,7,-1,1,17,-1,-1,3,17,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.7400519048390802,6.500000000000001,0.0,0.0,0.9839089345154072,3.5000000000000004,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.029240445519556915,0.0,-0.033246161171957674,0.0,0.0,-0.006321929002149643,0.0061789840700215435,0.0,0.0,-0.004005266522416672,0.01102517276978662,0.019416161652346477]},{"feature":[19,-1,7,-1,4,9,-1,17,-1,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.09068361409973183,1.5000000000000002,0.0,1.5000000000000002,0.0,0.0,0.5579044266708318,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,0,11,0,0],"right":[2,0,4,0,10,7,0,9,0,0,12,0,0],"value":[0.0,-0.029150139014580807,0.0,-0.03298197304036439,0.0,0.0,0.014509415540989154,0.0,-0.01124065578254264,0.0008856773251266628,0.0,-0.0013188965644496877,0.017623280837375556]},{"feature":[19,-1,7,-1,4,9,-1,20,-1,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.09068361409973183,1.5000000000000002,0.0,1.5000000000000002,0.0,0.0,0.5579044266708318,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,0,11,0,0],"right":[2,0,4,0,10,7,0,9,0,0,12,0,0],"value":[0.0,-0.028921924976391525,0.0,-0.033008319582807547,0.0,0.0,0.01416704113770269,0.0,0.004980049754895813,-0.0064922063789804975,0.0,-0.0010346632382031964,0.017312555734192506]},{"feature":[19,-1,7,-1,4,9,-1,20,-1,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.09068361409973183,1.5000000000000002,0.0,1.5000000000000002,0.0,0.0,0.6027747137247438,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,0,11,0,0],"right":[2,0,4,0,10,7,0,9,0,0,12,0,0],"value":[0.0,-0.028766442756601496,0.0,-0.032830944873973165,0.0,0.0,0.013784220195435,0.0,0.005071719548690766,-0.0063836336898791994,0.0,0.0009970105526849347,0.017450400871149557]},{"feature":[19,-1,7,-1,17,14,5,-1,-1,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,5.500000000000001,0.9056764827342051,0.13207623446444114,0.0,0.0,0.0,0.5579044266708318,0.0,0.0],"left":[1,0,3,0,5,6,7,0,0,0,11,0,0],"right":[2,0,4,0,10,9,8,0,0,0,12,0,0],"value":[0.0,-0.02863699403131269,0.0,-0.033698024065743896,0.0,0.0,0.0,-0.012458574877978815,0.00046333621185863844,0.013033493925011476,0.0,0.0005900199113769003,0.01644995646406242]},{"feature":[19,-1,7,-1,4,20,-1,17,-1,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.09068361409973183,1.5000000000000002,0.0,3.5000000000000004,0.0,0.0,0.6027747137247438,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,0,11,0,0],"right":[2,0,4,0,10,7,0,9,0,0,12,0,0],"value":[0.0,-0.028505585081583084,0.0,-0.03357421804764916,0.0,0.0,0.006683131847223349,0.0,-0.009053000073138435,0.0036630854488954563,0.0,0.0009158633493558656,0.01701194185409723]},{"feature":[19,-1,7,-1,1,5,-1,-1,14,-1,17,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.8416864984174791,0.12000000000000008,0.0,0.0,0.5556618045961942,0.0,3.5000000000000004,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,0,11,0,0],"right":[2,0,4,0,8,7,0,0,10,0,12,0,0],"value":[0.0,-0.02833708786579312,0.0,-0.03285066520820112,0.0,0.0,-0.0066009918203897965,0.005163887979818094,0.0,-0.002550819812937201,0.0,0.0020648140972807324,0.017558457878362143]},{"feature":[19,-1,7,-1,17,14,5,-1,-1,-1,5,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,7.500000000000001,0.9208974068560646,0.13207623446444114,0.0,0.0,0.0,0.16273565144532892,0.0,0.0],"left":[1,0,3,0,5,6,7,0,0,0,11,0,0],"right":[2,0,4,0,10,9,8,0,0,0,12,0,0],"value":[0.0,-0.028207353271963633,0.0,-0.03338849272962764,0.0,0.0,0.0,-0.010896098011246129,0.0015086219511910566,0.013486240464407828,0.0,0.0062092947688710855,0.01938123315152137]},{"feature":[19,-1,7,-1,4,9,-1,20,-1,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.09068361409973183,1.5000000000000002,0.0,1.5000000000000002,0.0,0.0,0.5579044266708318,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,0,11,0,0],"right":[2,0,4,0,10,7,0,9,0,0,12,0,0],"value":[0.0,-0.027994927162642576,0.0,-0.03515124369736893,0.0,0.0,0.013373659181422859,0.0,0.005001365901977169,-0.00654258121644183,0.0,-0.0011084589949256296,0.016424492615924696]},{"feature":[19,-1,7,-1,17,14,5,-1,-1,-1,5,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,5.500000000000001,0.9056764827342051,0.13207623446444114,0.0,0.0,0.0,0.15805837253719549,0.0,0.0],"left":[1,0,3,0,5,6,7,0,0,0,11,0,0],"right":[2,0,4,0,10,9,8,0,0,0,12,0,0],"value":[0.0,-0.027879873330920377,0.0,-0.03415185867407998,0.0,0.0,0.0,-0.012049742432953255,0.0004578912595752047,0.011323505881475184,0.0,0.0046063179503387855,0.01806529005006432]},{"feature":[19,-1,7,-1,1,17,-1,9,-1,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.8416864984174791,1.5000000000000002,0.0,30.500000000000004,0.0,0.0,0.5556618045961942,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,0,11,0,0],"right":[2,0,4,0,10,7,0,9,0,0,12,0,0],"value":[0.0,-0.02785679626490177,0.0,-0.03293339294336715,0.0,0.0,-0.01081570301451557,0.0,-0.002232568108472168,0.009717541942874688,0.0,-0.0026323367146705496,0.014750642530316795]},{"feature":[19,-1,7,-1,4,20,-1,-1,14,5,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.09068361409973183,1.5000000000000002,0.0,0.0,0.6027747137247438,0.15805837253719549,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.027569790042439833,0.0,-0.03220916185094234,0.0,0.0,0.006194382041281984,-0.00459663991821349,0.0,0.0,-0.01054574261879853,0.009281977867008523,0.01579328394164527]},{"feature":[19,-1,7,-1,14,5,20,-1,-1,-1,4,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.7529684458842033,0.1636838910648435,1.5000000000000002,0.0,0.0,0.0,0.09068361409973183,0.0,0.0],"left":[1,0,3,0,5,6,7,0,0,0,11,0,0],"right":[2,0,4,0,10,9,8,0,0,0,12,0,0],"value":[0.0,-0.027407795376546047,0.0,-0.03161160291028598,0.0,0.0,0.0,0.0013274815119415923,-0.0146431318386939,0.005146298623968724,0.0,0.005160304332699489,0.016600481310683528]},{"feature":[19,-1,7,-1,3,5,-1,17,9,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.9760686553986999,0.12832752437332062,0.0,7.500000000000001,31.500000000000004,0.0,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,8,9,0,0,0,0],"right":[2,0,4,0,12,7,0,11,10,0,0,0,0],"value":[0.0,-0.027194672707542954,0.0,-0.03164565469818476,0.0,0.0,-0.006258156243885123,0.0,0.0,-0.0052125423977116645,0.008681789957109786,0.015674102584555025,0.015697761196311846]},{"feature":[19,-1,7,-1,4,20,-1,-1,14,5,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.09068361409973183,1.5000000000000002,0.0,0.0,0.6027747137247438,0.15805837253719549,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.02701350996801201,0.0,-0.03264723305860333,0.0,0.0,0.005918293509849256,-0.004606467367728622,0.0,0.0,-0.010654219493926441,0.009089616375081534,0.015375489369756782]},{"feature":[19,-1,7,-1,4,20,-1,-1,14,5,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.09068361409973183,1.5000000000000002,0.0,0.0,0.6027747137247438,0.15805837253719549,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.027025567210084284,0.0,-0.03376575845676871,0.0,0.0,0.005936999764705971,-0.0043004239089707245,0.0,0.0,-0.0106010359714233,0.009016915264710278,0.015280900460820313]},{"feature":[19,-1,7,-1,1,-1,14,17,-1,5,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.7400519048390802,0.0,0.9441804761364593,5.500000000000001,0.0,0.15805837253719549,0.0,0.0,0.0],"left":[1,0,3,0,5,0,7,8,0,10,0,0,0],"right":[2,0,4,0,6,0,12,9,0,11,0,0,0],"value":[0.0,-0.02695170818700629,0.0,-0.03192576428303675,0.0,-0.0026109222357431137,0.0,0.0,-0.002179504022326282,0.0,0.001118320598825812,0.015583424138449388,0.01817967008444007]},{"feature":[19,-1,7,-1,4,9,-1,-1,5,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.09068361409973183,1.5000000000000002,0.0,0.0,0.14050920564634364,0.8730937293129465,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.02677145047193181,0.0,-0.030557048329709107,0.0,0.0,0.012679398457237602,-0.002560238221796989,0.0,0.0,-0.004030715993685109,0.012250494583356326,0.015915336515405065]},{"feature":[19,-1,7,-1,17,14,-1,-1,5,2,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,5.500000000000001,0.9402540526161026,0.0,0.0,0.15805837253719549,1.5000000000000002,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.026547566156895314,0.0,-0.030124739106531403,0.0,0.0,-0.004063338194589772,0.011465708482348685,0.0,0.0,0.013570646252331732,-0.0016011239768892631,0.016037777795431616]},{"feature":[19,-1,7,-1,3,5,-1,17,9,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.9760686553986999,0.12832752437332062,0.0,7.500000000000001,31.500000000000004,0.0,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,8,9,0,0,0,0],"right":[2,0,4,0,12,7,0,11,10,0,0,0,0],"value":[0.0,-0.026279459726714673,0.0,-0.028434862782082876,0.0,0.0,-0.006114723543788614,0.0,0.0,-0.0051103950191665175,0.008726650135157927,0.01421513554425879,0.014222137734610533]},{"feature":[19,-1,7,-1,17,14,-1,-1,5,2,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,5.500000000000001,0.9402540526161026,0.0,0.0,0.15805837253719549,1.5000000000000002,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.026025198985409413,0.0,-0.02816477211709723,0.0,0.0,-0.004246020587426912,0.010561737036496556,0.0,0.0,0.01304306308987098,-0.0017813646601228378,0.015732238126400573]},{"feature":[19,-1,7,-1,3,5,-1,17,9,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.9760686553986999,0.12832752437332062,0.0,7.500000000000001,31.500000000000004,0.0,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,8,9,0,0,0,0],"right":[2,0,4,0,12,7,0,11,10,0,0,0,0],"value":[0.0,-0.025911436523487277,0.0,-0.02818875530577435,0.0,0.0,-0.006189566634545612,0.0,0.0,-0.0053689024764753315,0.007995918460009119,0.014463827698689497,0.014025508226548727]},{"feature":[19,-1,7,-1,3,5,-1,17,9,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.9760686553986999,0.12832752437332062,0.0,7.500000000000001,31.500000000000004,0.0,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,8,9,0,0,0,0],"right":[2,0,4,0,12,7,0,11,10,0,0,0,0],"value":[0.0,-0.025804431909140123,0.0,-0.027146171482359302,0.0,0.0,-0.00612128532775274,0.0,0.0,-0.0049916536639341745,0.007688120894456594,0.013939923271199564,0.013699312781109545]},{"feature":[19,-1,7,-1,17,20,-1,-1,5,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,5.500000000000001,1.5000000000000002,0.0,0.0,0.15805837253719549,0.6365040866281786,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.0256766116647261,0.0,-0.026798074413697283,0.0,0.0,0.006796316110129742,-0.0055609103220033125,0.0,0.0,-0.00715041905005584,0.007573220166613728,0.015151598301740564]},{"feature":[19,-1,7,-1,3,5,-1,17,20,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.9760686553986999,0.12832752437332062,0.0,7.500000000000001,1.5000000000000002,0.0,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,8,9,0,0,0,0],"right":[2,0,4,0,12,7,0,11,10,0,0,0,0],"value":[0.0,-0.025516094336533388,0.0,-0.026337916777191543,0.0,0.0,-0.006260770512077523,0.0,0.0,0.010538949693449698,-0.003634985244821724,0.013150362240111221,0.013459101152374512]},{"feature":[19,-1,7,-1,3,5,-1,17,9,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.9760686553986999,0.12832752437332062,0.0,7.500000000000001,31.500000000000004,0.0,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,8,9,0,0,0,0],"right":[2,0,4,0,12,7,0,11,10,0,0,0,0],"value":[0.0,-0.025314037874592864,0.0,-0.026667779552718665,0.0,0.0,-0.006241477530371934,0.0,0.0,-0.00513041158348553,0.008036411844943369,0.012857754052991659,0.013431722439104902]},{"feature":[19,-1,7,-1,3,5,-1,20,-1,17,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.9760686553986999,0.12832752437332062,0.0,1.5000000000000002,0.0,5.500000000000001,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,10,0,0,0],"right":[2,0,4,0,12,7,0,9,0,11,0,0,0],"value":[0.0,-0.025111525809837925,0.0,-0.026590539853815057,0.0,0.0,-0.006167334186555867,0.0,0.014529366678427302,0.0,-0.005142872280411151,0.008768766170578356,0.013387056514896595]},{"feature":[19,-1,7,-1,14,17,20,-1,-1,5,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.9402540526161026,5.500000000000001,1.5000000000000002,0.0,0.0,0.15805837253719549,0.0,0.0,0.0],"left":[1,0,3,0,5,6,7,0,0,10,0,0,0],"right":[2,0,4,0,12,9,8,0,0,11,0,0,0],"value":[0.0,-0.024919245274170717,0.0,-0.026760031413078558,0.0,0.0,0.0,0.0053605456230352505,-0.008248766677166936,0.0,-0.00037579832631643654,0.01199685019855163,0.014916596361783642]},{"feature":[19,-1,7,-1,17,20,-1,-1,14,13,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,5.500000000000001,1.5000000000000002,0.0,0.0,0.5579044266708318,34.50000000000001,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.024598900493237413,0.0,-0.025804492079258296,0.0,0.0,0.006299337688878035,-0.005867768977316404,0.0,0.0,-0.013082911480103024,0.0102539946672137,0.012660893056772536]},{"feature":[19,-1,7,-1,17,20,-1,-1,14,13,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,5.500000000000001,1.5000000000000002,0.0,0.0,0.5579044266708318,30.500000000000004,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.024656869859146807,0.0,-0.02541301177445204,0.0,0.0,0.005975268215223714,-0.005693630982857982,0.0,0.0,-0.013027293043881399,0.009061798857603035,0.012435444164666931]},{"feature":[19,-1,9,-1,5,20,-1,-1,17,20,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,1.5000000000000002,0.0,1.0000000180025095e-35,1.5000000000000002,0.0,0.0,7.500000000000001,1.5000000000000002,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.024418429729274112,0.0,0.016127028682689625,0.0,0.0,0.00042055517648202775,-0.012897603964990265,0.0,0.0,0.010626353522391373,-0.0038974285243947708,0.011102889852243598]},{"feature":[19,-1,9,-1,5,20,-1,-1,20,-1,17,-1,-1],"threshold":[1.0000000180025095e-35,0.0,1.5000000000000002,0.0,1.0000000180025095e-35,1.5000000000000002,0.0,0.0,1.5000000000000002,0.0,8.500000000000002,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,0,11,0,0],"right":[2,0,4,0,8,7,0,0,10,0,12,0,0],"value":[0.0,-0.02415457893957226,0.0,0.015891254448033743,0.0,0.0,8.129329829885102e-06,-0.013116072544015013,0.0,0.013038553843295745,0.0,-0.0035129757348604193,0.009637254602926505]},{"feature":[19,-1,14,5,11,-1,-1,20,-1,17,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9488644879288765,0.12933324930428017,0.8673890315945177,0.0,0.0,1.5000000000000002,0.0,3.5000000000000004,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,8,0,10,0,0,0],"right":[2,0,12,7,6,0,0,9,0,11,0,0,0],"value":[0.0,-0.02402085236914352,0.0,0.0,0.0,-0.00982769459055394,0.0014810755404700757,0.0,0.012502136084563856,0.0,-0.005773458215601889,0.004009072136113505,0.013937592376689881]},{"feature":[19,-1,14,7,-1,5,-1,20,-1,17,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9488644879288765,0.7500000000000001,0.0,0.12933324930428017,0.0,1.5000000000000002,0.0,3.5000000000000004,0.0,0.0,0.0],"left":[1,0,3,4,0,6,0,8,0,10,0,0,0],"right":[2,0,12,5,0,7,0,9,0,11,0,0,0],"value":[0.0,-0.023878780067724523,0.0,0.0,-0.021813183080714005,0.0,-0.005179844719633926,0.0,0.013208680223295426,0.0,-0.005238482543000954,0.005328121016871496,0.013508961890930083]},{"feature":[19,-1,7,-1,14,5,11,-1,-1,20,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,0.9402540526161026,0.12933324930428017,0.8673890315945177,0.0,0.0,1.5000000000000002,0.0,0.0,0.0],"left":[1,0,3,0,5,6,7,0,0,10,0,0,0],"right":[2,0,4,0,12,9,8,0,0,11,0,0,0],"value":[0.0,-0.02372995838951786,0.0,-0.023562982669791982,0.0,0.0,0.0,-0.009146718983933664,0.0031779017158216445,0.0,0.013217051236014977,0.0010741547313861974,0.013658224321779093]},{"feature":[19,-1,7,-1,17,20,-1,-1,14,13,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,5.500000000000001,2.5000000000000004,0.0,0.0,0.5579044266708318,34.50000000000001,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.02356792493276585,0.0,-0.022665918901887527,0.0,0.0,0.0009189044126642597,-0.009597733011996554,0.0,0.0,-0.012460808741440748,0.008735984217491648,0.011393652933154932]},{"feature":[19,-1,14,17,5,-1,-1,14,13,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9402540526161026,7.500000000000001,0.13207623446444114,0.0,0.0,0.5579044266708318,41.50000000000001,0.0,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,8,9,0,0,0,0],"right":[2,0,12,7,6,0,0,11,10,0,0,0,0],"value":[0.0,-0.02339539852490124,0.0,0.0,0.0,-0.009923566907776718,-0.00040417077830259607,0.0,0.0,-0.01278652733166733,0.009643302864040472,0.009021843166616592,0.012107767252427569]},{"feature":[19,-1,14,17,5,-1,-1,14,13,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9402540526161026,7.500000000000001,0.13207623446444114,0.0,0.0,0.5579044266708318,41.50000000000001,0.0,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,8,9,0,0,0,0],"right":[2,0,12,7,6,0,0,11,10,0,0,0,0],"value":[0.0,-0.0232314907932381,0.0,0.0,0.0,-0.009869117280337758,-0.0003091662157925123,0.0,0.0,-0.01205162918588676,0.009946197656499981,0.008660522328945314,0.011684062245384033]},{"feature":[19,-1,7,-1,17,20,-1,-1,11,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,5.500000000000001,2.5000000000000004,0.0,0.0,0.8748403378185962,0.5880639313617806,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.023065939632704965,0.0,-0.021825368721464188,0.0,0.0,0.001302427804886437,-0.009767237524424219,0.0,0.0,-0.009157795860553276,0.007211501515568008,0.01346882305131725]},{"feature":[19,-1,7,-1,17,20,-1,-1,11,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,5.500000000000001,2.5000000000000004,0.0,0.0,0.8748403378185962,0.5880639313617806,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.022890315915516983,0.0,-0.021385932779303195,0.0,0.0,0.0013124251336027483,-0.009210570333461869,0.0,0.0,-0.008834709542943095,0.006870074106223552,0.013024582001850585]},{"feature":[19,-1,7,-1,5,9,-1,-1,20,-1,4,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,1.0000000180025095e-35,1.5000000000000002,0.0,0.0,1.5000000000000002,0.0,0.09991944631692354,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,0,11,0,0],"right":[2,0,4,0,8,7,0,0,10,0,12,0,0],"value":[0.0,-0.022684116129914993,0.0,-0.02107804568539346,0.0,0.0,0.009941749039499627,-0.00540162456798493,0.0,0.014867328009041345,0.0,-0.002013777895302233,0.009289542846056964]},{"feature":[19,-1,14,5,20,-1,-1,20,-1,-1,20,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9402540526161026,0.12933324930428017,1.5000000000000002,0.0,0.0,1.5000000000000002,0.0,0.0,2.5000000000000004,0.0,0.0],"left":[1,0,3,4,5,0,0,8,0,0,11,0,0],"right":[2,0,10,7,6,0,0,9,0,0,12,0,0],"value":[0.0,-0.02250198960923021,0.0,0.0,0.0,6.0556379065425195e-05,-0.011272934651427554,0.0,0.011746770237842928,0.00016533135165578336,0.0,0.01372408993728592,-0.001997548411657237]},{"feature":[19,-1,7,-1,5,9,-1,20,-1,-1,20,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,1.0000000180025095e-35,1.5000000000000002,0.0,1.5000000000000002,0.0,0.0,1.5000000000000002,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,0,11,0,0],"right":[2,0,4,0,10,7,0,9,0,0,12,0,0],"value":[0.0,-0.022321352354672426,0.0,-0.020808789832919786,0.0,0.0,0.009440532847171371,0.0,0.0019608782119948077,-0.011458602786491431,0.0,0.01416733880619859,0.0031135910475853885]},{"feature":[19,-1,7,-1,17,20,-1,-1,11,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,5.500000000000001,2.5000000000000004,0.0,0.0,0.8748403378185962,0.5880639313617806,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.022133307072882396,0.0,-0.020522362562700444,0.0,0.0,0.001166508598861306,-0.009181960019947649,0.0,0.0,-0.00849654146440363,0.006758481589907736,0.012269773274366133]},{"feature":[19,-1,7,-1,5,14,20,-1,-1,-1,20,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,1.0000000180025095e-35,0.8638928110891856,1.5000000000000002,0.0,0.0,0.0,1.5000000000000002,0.0,0.0],"left":[1,0,3,0,5,6,7,0,0,0,11,0,0],"right":[2,0,4,0,10,9,8,0,0,0,12,0,0],"value":[0.0,-0.021972710733363595,0.0,-0.020685502923410433,0.0,0.0,0.0,0.000496259038010428,-0.012569927499604002,0.005095905512444472,0.0,0.01369586799087484,0.0031257999025680666]},{"feature":[19,-1,7,-1,5,20,-1,9,-1,-1,20,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,1.0000000180025095e-35,1.5000000000000002,0.0,1.5000000000000002,0.0,0.0,1.5000000000000002,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,0,11,0,0],"right":[2,0,4,0,10,7,0,9,0,0,12,0,0],"value":[0.0,-0.02186671115178502,0.0,-0.02030623292336034,0.0,0.0,0.002889283408872603,0.0,0.008601442694677644,-0.011404907326563692,0.0,0.013640207915402372,0.0029556687435774664]},{"feature":[19,-1,7,-1,17,5,-1,-1,5,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,5.500000000000001,1.0000000180025095e-35,0.0,0.0,0.17119099965370907,0.6701344288855944,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.021623683253933306,0.0,-0.019954439817435037,0.0,0.0,-0.007566775488826092,0.0016679682036971222,0.0,0.0,-0.007232050895894178,0.0064409243343917875,0.011205442954623336]},{"feature":[19,-1,14,20,-1,5,9,-1,9,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9402540526161026,1.5000000000000002,0.0,0.19383165473445776,1.5000000000000002,0.0,30.500000000000004,0.0,0.0,0.0,0.0],"left":[1,0,3,4,0,6,7,0,9,0,0,0,0],"right":[2,0,12,5,0,11,8,0,10,0,0,0,0],"value":[0.0,-0.021416381737816105,0.0,0.0,0.005547366271011843,0.0,0.0,0.00723843033020433,0.0,-0.016885158351319172,-0.002547668691126032,0.0018582300342168635,0.010132611133115617]},{"feature":[19,-1,17,9,20,-1,-1,-1,14,13,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,7.500000000000001,4.500000000000001,2.5000000000000004,0.0,0.0,0.0,0.5579044266708318,41.50000000000001,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,0,9,10,0,0,0],"right":[2,0,8,7,6,0,0,0,12,11,0,0,0],"value":[0.0,-0.021215458606954684,0.0,0.0,0.0,0.009322256083725755,-0.007855730144802078,-0.0051517166510076755,0.0,0.0,-0.012607633752148645,0.01017569178766878,0.00976686644367041]},{"feature":[19,-1,14,20,-1,5,9,-1,-1,-1,4,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9402540526161026,1.5000000000000002,0.0,0.19383165473445776,1.5000000000000002,0.0,0.0,0.0,0.06430459524792172,0.0,0.0],"left":[1,0,3,4,0,6,7,0,0,0,11,0,0],"right":[2,0,10,5,0,9,8,0,0,0,12,0,0],"value":[0.0,-0.021043326541043544,0.0,0.0,0.005394467535483652,0.0,0.0,0.005764243811377854,-0.012145544980402835,0.0015604630331843,0.0,-0.0021606159954182568,0.013279428800444072]},{"feature":[19,-1,17,20,9,-1,-1,-1,14,13,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,7.500000000000001,2.5000000000000004,4.500000000000001,0.0,0.0,0.0,0.5579044266708318,41.50000000000001,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,0,9,10,0,0,0],"right":[2,0,8,7,6,0,0,0,12,11,0,0,0],"value":[0.0,-0.02084169725303763,0.0,0.0,0.0,0.008766621444788,-0.0028598922866354963,-0.00987317323702731,0.0,0.0,-0.011786672238942048,0.009548825615464461,0.009619367541098812]},{"feature":[19,-1,14,20,5,-1,-1,5,9,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9402540526161026,1.5000000000000002,0.13333333333333336,0.0,0.0,0.19383165473445776,1.5000000000000002,0.0,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,8,9,0,0,0,0],"right":[2,0,12,7,6,0,0,11,10,0,0,0,0],"value":[0.0,-0.02066599543455675,0.0,0.0,0.0,-1.2288996946150687e-05,0.011091545889305835,0.0,0.0,0.005158949278755127,-0.011888628337452922,0.0013390709641315011,0.010246881574774127]},{"feature":[19,-1,17,20,-1,10,-1,-1,14,13,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,7.500000000000001,2.5000000000000004,0.0,0.49747189879417425,0.0,0.0,0.5579044266708318,41.50000000000001,0.0,0.0,0.0],"left":[1,0,3,4,0,6,0,0,9,10,0,0,0],"right":[2,0,8,5,0,7,0,0,12,11,0,0,0],"value":[0.0,-0.02047955337382681,0.0,0.0,0.0009429307631994459,0.0,-0.0013611121642161641,-0.018629378414179238,0.0,0.0,-0.011569433499442321,0.009126476227938683,0.00950193614749972]},{"feature":[19,-1,14,20,5,-1,-1,5,9,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9402540526161026,1.5000000000000002,0.13333333333333336,0.0,0.0,0.19383165473445776,1.5000000000000002,0.0,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,8,9,0,0,0,0],"right":[2,0,12,7,6,0,0,11,10,0,0,0,0],"value":[0.0,-0.02028468216104616,0.0,0.0,0.0,0.00010165823581562294,0.01108749339202543,0.0,0.0,0.004980569346604882,-0.012246427068379502,0.0015024282615182486,0.010232293458094233]},{"feature":[19,-1,14,20,5,-1,-1,5,14,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9402540526161026,1.5000000000000002,0.13333333333333336,0.0,0.0,0.19383165473445776,0.7727364213019784,0.0,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,8,9,0,0,0,0],"right":[2,0,12,7,6,0,0,11,10,0,0,0,0],"value":[0.0,-0.020096616413675883,0.0,0.0,0.0,0.00041475435855476176,0.010631280346057688,0.0,0.0,-0.013733336401097413,-0.0007283944181130635,0.0012902542102639753,0.010217730950192827]},{"feature":[19,-1,20,-1,5,14,-1,-1,4,10,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,1.5000000000000002,0.0,0.19326702454130607,0.7727364213019784,0.0,0.0,0.09991944631692354,0.48953905701637274,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.019904836574328864,0.0,0.007570982246946023,0.0,0.0,-0.01378803023967938,0.0017430650150831407,0.0,0.0,0.0032195842168554,-0.009723478839627195,0.009050704601180445]},{"feature":[19,-1,20,5,-1,-1,5,14,-1,-1,4,-1,-1],"threshold":[1.0000000180025095e-35,0.0,1.5000000000000002,0.13333333333333336,0.0,0.0,0.19326702454130607,0.7727364213019784,0.0,0.0,0.09991944631692354,0.0,0.0],"left":[1,0,3,4,0,0,7,8,0,0,11,0,0],"right":[2,0,6,5,0,0,10,9,0,0,12,0,0],"value":[0.0,-0.01970537327978376,0.0,0.0,0.002523341909129997,0.012559377460148013,0.0,0.0,-0.013731381241862328,0.001501866266182808,0.0,-0.0024423463337136905,0.008675394743622243]},{"feature":[19,-1,20,-1,5,14,-1,-1,4,10,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,1.5000000000000002,0.0,0.19326702454130607,0.7727364213019784,0.0,0.0,0.09991944631692354,0.48953905701637274,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.01953538262587015,0.0,0.007395939492503401,0.0,0.0,-0.013435943008295113,0.0016239820469432346,0.0,0.0,0.003117763249090083,-0.008917194460645646,0.008305900227028096]},{"feature":[19,-1,14,20,-1,5,9,-1,9,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9402540526161026,1.5000000000000002,0.0,0.19383165473445776,1.5000000000000002,0.0,30.500000000000004,0.0,0.0,0.0,0.0],"left":[1,0,3,4,0,6,7,0,9,0,0,0,0],"right":[2,0,12,5,0,11,8,0,10,0,0,0,0],"value":[0.0,-0.01935093741485298,0.0,0.0,0.005193668937790834,0.0,0.0,0.005148131897929986,0.0,-0.016168616282220237,-0.0022000368286927987,0.001022414222175041,0.009900610218040964]},{"feature":[19,-1,14,20,-1,5,9,-1,14,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.9402540526161026,1.5000000000000002,0.0,0.2933180370227432,1.5000000000000002,0.0,0.7696196815719588,0.0,0.0,0.0,0.0],"left":[1,0,3,4,0,6,7,0,9,0,0,0,0],"right":[2,0,12,5,0,11,8,0,10,0,0,0,0],"value":[0.0,-0.01917721479677927,0.0,0.0,0.005086762400486053,0.0,0.0,0.005300707730530864,0.0,-0.012355317778483081,-0.00011530184590401128,0.003513360215247886,0.009882134240875041]},{"feature":[19,-1,7,-1,20,5,-1,-1,14,5,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,1.5000000000000002,0.13333333333333336,0.0,0.0,0.7870037055932765,0.2933180370227432,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.01901225041896942,0.0,-0.019885161491299205,0.0,0.0,0.002466013504775788,0.012859475659210166,0.0,0.0,-0.009111543791286536,0.0045208792927491194,0.004824716322945478]},{"feature":[19,-1,7,-1,20,-1,14,5,-1,9,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,1.5000000000000002,0.0,0.7870037055932765,0.18620780590717306,0.0,12.500000000000002,0.0,0.0,0.0],"left":[1,0,3,0,5,0,7,8,0,10,0,0,0],"right":[2,0,4,0,6,0,12,9,0,11,0,0,0],"value":[0.0,-0.018825035492140225,0.0,-0.020084358220639028,0.0,0.007744542062334868,0.0,0.0,-0.01168830986796932,0.0,0.006311760739851585,-0.005373156416179765,0.004392162104198928]},{"feature":[19,-1,7,-1,20,-1,5,14,-1,17,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,1.5000000000000002,0.0,0.28996134511297905,0.7497348453485532,0.0,9.500000000000002,0.0,0.0,0.0],"left":[1,0,3,0,5,0,7,8,0,10,0,0,0],"right":[2,0,4,0,6,0,12,9,0,11,0,0,0],"value":[0.0,-0.018698871387733663,0.0,-0.020345649089571666,0.0,0.007731044203530112,0.0,0.0,-0.008821445139549869,0.0,-0.0029533290022537395,0.00864151606853087,0.005123408760922325]},{"feature":[19,-1,7,-1,17,-1,14,13,14,-1,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,1.5000000000000002,0.0,0.9402540526161026,39.50000000000001,0.5833938301109745,0.0,0.0,0.0,0.0],"left":[1,0,3,0,5,0,7,8,9,0,0,0,0],"right":[2,0,4,0,6,0,12,11,10,0,0,0,0],"value":[0.0,-0.018512688312358274,0.0,-0.0193163662219779,0.0,-0.007469420793817127,0.0,0.0,0.0,-0.006496782349230016,0.0023373914690202197,0.009407472103269992,0.010199087916182669]},{"feature":[19,-1,7,-1,17,20,-1,5,-1,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,7.500000000000001,1.5000000000000002,0.0,0.2903607113874665,0.0,0.0,0.5579044266708318,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,0,11,0,0],"right":[2,0,4,0,10,7,0,9,0,0,12,0,0],"value":[0.0,-0.018334159076452267,0.0,-0.019106490785321076,0.0,0.0,0.004817999021273916,0.0,-0.007656021890987314,0.00360422146694325,0.0,-0.002673192149626461,0.009021028693089858]},{"feature":[19,-1,7,-1,20,-1,5,17,-1,5,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,1.5000000000000002,0.0,0.28996134511297905,3.5000000000000004,0.0,0.1469975935949371,0.0,0.0,0.0],"left":[1,0,3,0,5,0,7,8,0,10,0,0,0],"right":[2,0,4,0,6,0,12,9,0,11,0,0,0],"value":[0.0,-0.018155683438432844,0.0,-0.019153256631172875,0.0,0.007096276415674754,0.0,0.0,-0.009891184573684975,0.0,-0.005459680907045045,0.005131564383519794,0.005503506626253555]},{"feature":[19,-1,7,-1,20,5,-1,-1,5,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,1.5000000000000002,0.13333333333333336,0.0,0.0,0.28996134511297905,0.7870037055932765,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.01795808637495345,0.0,-0.01949786789555242,0.0,0.0,0.002326627393331599,0.011736912832588181,0.0,0.0,-0.007831873528563515,0.0022374615726325413,0.005364055776399392]},{"feature":[19,-1,7,-1,17,9,20,-1,-1,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,7.500000000000001,4.500000000000001,2.5000000000000004,0.0,0.0,0.0,0.5556618045961942,0.0,0.0],"left":[1,0,3,0,5,6,7,0,0,0,11,0,0],"right":[2,0,4,0,10,9,8,0,0,0,12,0,0],"value":[0.0,-0.017793352103268715,0.0,-0.020431000606855928,0.0,0.0,0.0,0.009475290897909706,-0.009157729763723968,-0.0039701386200962545,0.0,-0.0027210155305645712,0.008795674167566405]},{"feature":[19,-1,7,-1,17,5,-1,20,-1,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,7.500000000000001,1.0000000180025095e-35,0.0,1.5000000000000002,0.0,0.0,0.5579044266708318,0.0,0.0],"left":[1,0,3,0,5,6,0,8,0,0,11,0,0],"right":[2,0,4,0,10,7,0,9,0,0,12,0,0],"value":[0.0,-0.0176388571947388,0.0,-0.01896924332791558,0.0,0.0,-0.006415117458938673,0.0,0.009796086066643676,-0.0012082051665638983,0.0,-0.002390566369032629,0.008648321785580752]},{"feature":[19,-1,7,-1,20,5,-1,-1,5,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,1.5000000000000002,0.13333333333333336,0.0,0.0,0.28996134511297905,0.7696196815719588,0.0,0.0,0.0],"left":[1,0,3,0,5,6,0,0,9,10,0,0,0],"right":[2,0,4,0,8,7,0,0,12,11,0,0,0],"value":[0.0,-0.017481387261724695,0.0,-0.01818640247171807,0.0,0.0,0.002086276307215665,0.011552315843959628,0.0,0.0,-0.007909209305149082,0.0017045757864533907,0.005282201843947859]},{"feature":[19,-1,20,5,-1,-1,5,17,-1,5,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,1.5000000000000002,0.13333333333333336,0.0,0.0,0.28996134511297905,3.5000000000000004,0.0,0.1469975935949371,0.0,0.0,0.0],"left":[1,0,3,4,0,0,7,8,0,10,0,0,0],"right":[2,0,6,5,0,0,12,9,0,11,0,0,0],"value":[0.0,-0.017307364662637714,0.0,0.0,0.0016973983197428786,0.010968934190351456,0.0,0.0,-0.010393151883540445,0.0,-0.006047789190177409,0.0038970434412553077,0.004368009317893341]},{"feature":[19,-1,20,10,3,-1,-1,-1,5,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,1.5000000000000002,0.5714478790760041,0.6954244647433753,0.0,0.0,0.0,0.28996134511297905,0.7696196815719588,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,0,9,10,0,0,0],"right":[2,0,8,7,6,0,0,0,12,11,0,0,0],"value":[0.0,-0.01714605973426951,0.0,0.0,0.0,0.009652825618746697,-0.0014184805160585262,0.013387959010280864,0.0,0.0,-0.008687103508721388,0.0009256147372228554,0.004157345815572851]},{"feature":[19,-1,20,5,4,-1,-1,-1,5,17,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,1.5000000000000002,0.13333333333333336,0.18639079220585214,0.0,0.0,0.0,0.28996134511297905,3.5000000000000004,0.0,0.0,0.0],"left":[1,0,3,4,5,0,0,0,9,10,0,0,0],"right":[2,0,8,7,6,0,0,0,12,11,0,0,0],"value":[0.0,-0.01695913505583674,0.0,0.0,0.0,-0.002410574494600741,0.009567383835241982,0.010829655432395805,0.0,0.0,-0.010059505222428516,-0.0008550001558937061,0.003918798482642889]},{"feature":[19,-1,7,-1,17,9,20,-1,-1,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,7.500000000000001,4.500000000000001,2.5000000000000004,0.0,0.0,0.0,0.5556618045961942,0.0,0.0],"left":[1,0,3,0,5,6,7,0,0,0,11,0,0],"right":[2,0,4,0,10,9,8,0,0,0,12,0,0],"value":[0.0,-0.016793207113588268,0.0,-0.018296409083420444,0.0,0.0,0.0,0.00895409083505374,-0.009013742784488118,-0.003966529569607843,0.0,-0.003218388478448528,0.008388248494024999]},{"feature":[19,-1,20,-1,5,-1,17,10,-1,4,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,1.5000000000000002,0.0,0.1469975935949371,0.0,8.500000000000002,0.48953905701637274,0.0,0.09991944631692354,0.0,0.0,0.0],"left":[1,0,3,0,5,0,7,8,0,10,0,0,0],"right":[2,0,4,0,6,0,12,9,0,11,0,0,0],"value":[0.0,-0.016598830297725266,0.0,0.006107633557467716,0.0,-0.007781906860487455,0.0,0.0,0.0033054462507929247,0.0,-0.013974362252931164,0.0034632740454506017,0.007369917858871519]},{"feature":[19,-1,20,5,-1,-1,5,9,-1,14,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,1.5000000000000002,0.13333333333333336,0.0,0.0,0.28996134511297905,1.5000000000000002,0.0,0.7696196815719588,0.0,0.0,0.0],"left":[1,0,3,4,0,0,7,8,0,10,0,0,0],"right":[2,0,6,5,0,0,12,9,0,11,0,0,0],"value":[0.0,-0.01644347519309433,0.0,0.0,0.001746508950427452,0.01044436274529867,0.0,0.0,0.0049823900292025524,0.0,-0.009843477036970256,-0.0004842843429195365,0.0041828646222553814]},{"feature":[19,-1,20,-1,5,-1,17,10,-1,4,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,1.5000000000000002,0.0,0.1469975935949371,0.0,8.500000000000002,0.48953905701637274,0.0,0.09991944631692354,0.0,0.0,0.0],"left":[1,0,3,0,5,0,7,8,0,10,0,0,0],"right":[2,0,4,0,6,0,12,9,0,11,0,0,0],"value":[0.0,-0.016164190314780242,0.0,0.005923808477472176,0.0,-0.007907995672467515,0.0,0.0,0.0034562807642436696,0.0,-0.013467302922956639,0.0034285622241117795,0.007250031657782312]},{"feature":[19,-1,7,-1,17,-1,20,-1,5,-1,14,-1,-1],"threshold":[1.0000000180025095e-35,0.0,0.7500000000000001,0.0,1.5000000000000002,0.0,1.5000000000000002,0.0,0.1469975935949371,0.0,0.5579044266708318,0.0,0.0],"left":[1,0,3,0,5,0,7,0,9,0,11,0,0],"right":[2,0,4,0,6,0,8,0,10,0,12,0,0],"value":[0.0,-0.015828700363724836,0.0,-0.017395083596317317,0.0,-0.006988365963696314,0.0,0.007251819051544626,0.0,-0.005009860754997112,0.0,-0.0032536438432270074,0.005862295802078939]},{"feature":[19,-1,20,14,13,-1,1,-1,-1,5,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,2.5000000000000004,0.5833938301109745,43.50000000000001,0.0,0.6591803518190976,0.0,0.0,0.14487515959710598,0.0,0.0,0.0],"left":[1,0,3,4,5,0,7,0,0,10,0,0,0],"right":[2,0,12,9,6,0,8,0,0,11,0,0,0],"value":[0.0,-0.015858511284001602,0.0,0.0,0.0,-0.00895348835514995,0.0,-0.0018486650983325,0.01707182460867478,0.0,0.00025980093079372055,0.009585360779834124,-0.005640919710539365]},{"feature":[19,-1,17,-1,7,-1,5,-1,14,3,-1,-1,-1],"threshold":[1.0000000180025095e-35,0.0,1.5000000000000002,0.0,0.7500000000000001,0.0,1.0000000180025095e-35,0.0,0.9488644879288765,0.6954244647433753,0.0,0.0,0.0],"left":[1,0,3,0,5,0,7,0,9,10,0,0,0],"right":[2,0,4,0,6,0,8,0,12,11,0,0,0],"value":[0.0,-0.015862217442205614,0.0,-0.0077760765415929335,0.0,-0.015582557313372008,0.0,-0.0006787942067795346,0.0,0.0,0.010371160483732239,0.0005541249882074775,0.012398601732746517]}]} diff --git a/src/semble/search.py b/src/semble/search.py index d1c18b78..7df4fac4 100644 --- a/src/semble/search.py +++ b/src/semble/search.py @@ -6,6 +6,8 @@ from semble.index.dense import SelectableBasicBackend from semble.index.sparse import selector_to_mask from semble.ranking import apply_query_boost, boost_multi_chunk_files, rerank_topk, resolve_alpha +from semble.ranking.boosting import query_boost_deltas +from semble.ranking.learned import RankingSignals, apply_learned_ranker, load_ranker from semble.tokens import tokenize from semble.types import Chunk, SearchResult @@ -63,7 +65,7 @@ def _search_bm25( return [SearchResult(chunk=chunks[i], score=float(scores[i])) for i in indices if scores[i] > 0] -def search( +def score_candidates( query: str, model: StaticModel, semantic_index: SelectableBasicBackend, @@ -73,22 +75,19 @@ def search( alpha: float | None = None, selector: npt.NDArray[np.int_] | None = None, rerank: bool = True, -) -> list[SearchResult]: - """Hybrid search: alpha-weighted combination of semantic and BM25 scores. - - Both score sets are converted to RRF scores before combining, so alpha has - a consistent meaning regardless of raw score magnitude. +) -> RankingSignals: + """Retrieve and fuse candidates, apply the code-tuned boosts, and return every intermediate score. :param query: Search query string. :param model: Embedding model for semantic search. :param semantic_index: Pre-built semantic (vector) index. :param bm25_index: Pre-built BM25 index. :param chunks: All indexed chunks (parallel to BM25 index). - :param top_k: Number of results to return. + :param top_k: Number of results the caller wants; candidates are over-fetched from this. :param alpha: Weight for semantic score (1-alpha goes to BM25). None = auto-detect based on query type. :param selector: Optional array of chunk indices to filter results by. - :param rerank: Whether to perform code-tuned reranking. On by default for code search, off for docs search. - :return: List of search results sorted by combined score descending. + :param rerank: Apply the multi-chunk and query boosts. When False, boosted equals fused. + :return: The ranking signals for this query. """ alpha_weight = resolve_alpha(query, alpha) @@ -116,16 +115,58 @@ def search( } # Remove chunks that have 0.0 score - combined_scores = {chunk: score for chunk, score in combined_scores.items() if score} + fused = {chunk: score for chunk, score in combined_scores.items() if score} + if not rerank: + return RankingSignals(alpha_weight, semantic_scores, bm25_scores, fused, {}, {}, {}, fused) + + # Boost files with multiple relevant chunks. + with_file_boost = dict(fused) + boost_multi_chunk_files(with_file_boost) + file_boost = {c: s - fused[c] for c, s in with_file_boost.items() if s != fused[c]} + # Boost queries with specific identifiers in them. + boosted = apply_query_boost(with_file_boost, query, chunks) + stem_boost, definition_boost = query_boost_deltas(with_file_boost, query, chunks) + return RankingSignals( + alpha_weight, semantic_scores, bm25_scores, fused, file_boost, stem_boost, definition_boost, boosted + ) + + +def search( + query: str, + model: StaticModel, + semantic_index: SelectableBasicBackend, + bm25_index: BM25, + chunks: list[Chunk], + top_k: int, + alpha: float | None = None, + selector: npt.NDArray[np.int_] | None = None, + rerank: bool = True, +) -> list[SearchResult]: + """Hybrid search: alpha-weighted combination of semantic and BM25 scores. + Both score sets are converted to RRF scores before combining, so alpha has + a consistent meaning regardless of raw score magnitude. + + :param query: Search query string. + :param model: Embedding model for semantic search. + :param semantic_index: Pre-built semantic (vector) index. + :param bm25_index: Pre-built BM25 index. + :param chunks: All indexed chunks (parallel to BM25 index). + :param top_k: Number of results to return. + :param alpha: Weight for semantic score (1-alpha goes to BM25). None = auto-detect based on query type. + :param selector: Optional array of chunk indices to filter results by. + :param rerank: Whether to perform code-tuned reranking. On by default for code search, off for docs search. + :return: List of search results sorted by combined score descending. + """ + signals = score_candidates(query, model, semantic_index, bm25_index, chunks, top_k, alpha, selector, rerank) if rerank: - # Boost files with multiple relevant chunks. - boost_multi_chunk_files(combined_scores) - # Boost queries with specific identifiers in them. - combined_scores = apply_query_boost(combined_scores, query, chunks) + scores = signals.boosted + if scores and (ranker := load_ranker()) is not None: + # Correct the hand-tuned scores with the learned ranker. + scores = apply_learned_ranker(signals, ranker) # Rerank the top-k results by applying path-based penalties. - ranked = rerank_topk(combined_scores, top_k, penalise_paths=alpha_weight < 1.0) + ranked = rerank_topk(scores, top_k, penalise_paths=signals.alpha < 1.0) else: - sorted_by_score = sorted(combined_scores.items(), key=lambda x: x[1], reverse=True) + sorted_by_score = sorted(signals.fused.items(), key=lambda x: x[1], reverse=True) ranked = sorted_by_score[:top_k] return [SearchResult(chunk=chunk, score=score) for chunk, score in ranked] diff --git a/tests/test_learned_ranker.py b/tests/test_learned_ranker.py new file mode 100644 index 00000000..92c113ee --- /dev/null +++ b/tests/test_learned_ranker.py @@ -0,0 +1,82 @@ +import numpy as np +import pytest + +from semble.ranking import learned +from semble.ranking.learned import FEATURES, RankingSignals, TreeEnsemble, apply_learned_ranker, ranking_features +from tests.conftest import make_chunk + +# Two trees over a 2-feature input: tree 0 splits on x0 <= 0.5, tree 1 is a single leaf. +_TOY = { + "features": ["a", "b"], + "trees": [ + { + "feature": [0, -1, -1], + "threshold": [0.5, 0.0, 0.0], + "left": [1, 0, 0], + "right": [2, 0, 0], + "value": [0.0, -1.0, 2.0], + }, + {"feature": [-1], "threshold": [0.0], "left": [0], "right": [0], "value": [0.25]}, + ], +} + + +def _signals() -> RankingSignals: + a = make_chunk("def parse(): ...", "src/parser.py") + b = make_chunk("def parse_all(): ...", "src/parser.py") + c = make_chunk("def load(): ...", "tests/test_loader.py") + return RankingSignals( + alpha=0.5, + semantic={a: 0.9, c: 0.4}, + bm25={b: 7.0, a: 5.0}, + fused={a: 0.02, b: 0.01, c: 0.005}, + file_boost={a: 0.004}, + stem_boost={}, + definition_boost={b: 0.03}, + boosted={a: 0.024, b: 0.04, c: 0.005}, + ) + + +def test_tree_ensemble_predict() -> None: + """Rows follow x <= threshold to the left; outputs sum over trees.""" + ensemble = TreeEnsemble.from_dict(_TOY) + x = np.array([[0.2, 9.0], [0.5, 0.0], [0.7, 0.0]]) + assert ensemble.predict(x) == pytest.approx([-0.75, -0.75, 2.25]) + assert ensemble.predict(np.empty((0, 2))).shape == (0,) + + +def test_ranking_features() -> None: + """The pool is ordered by boosted score and every column of FEATURES is filled.""" + signals = _signals() + pool, x = ranking_features(signals) + assert [c.content for c in pool] == ["def parse_all(): ...", "def parse(): ...", "def load(): ..."] + assert x.shape == (3, len(FEATURES)) + row = dict(zip(FEATURES, x[0])) + assert row["final_rank"] == 1 and row["final_rel"] == 1.0 + assert row["in_bm25"] == 1.0 and row["in_semantic"] == 0.0 and row["semantic_rank"] == 100 + assert row["file_chunks_in_pool"] == 2 and row["is_file_best"] == 1.0 + assert dict(zip(FEATURES, x[1]))["is_file_best"] == 0.0 + assert dict(zip(FEATURES, x[2]))["is_penalised_path"] == 1.0 + assert ranking_features(RankingSignals(0.5, {}, {}, {}, {}, {}, {}, {})) == ([], pytest.approx(np.empty((0, 21)))) + + +def test_apply_learned_ranker_scales_boosted_scores() -> None: + """Each candidate's boosted score is multiplied by exp(correction); the candidate set is unchanged.""" + signals = _signals() + ensemble = TreeEnsemble.from_dict({**_TOY, "features": list(FEATURES)}) + scores = apply_learned_ranker(signals, ensemble) + assert set(scores) == set(signals.boosted) + pool, x = ranking_features(signals) + for chunk, correction in zip(pool, ensemble.predict(x)): + assert scores[chunk] == pytest.approx(signals.boosted[chunk] * np.exp(correction)) + + +def test_packaged_ranker_matches_features(monkeypatch: pytest.MonkeyPatch) -> None: + """The shipped ranker.json matches FEATURES; SEMBLE_LEARNED_RANKER=0 disables it.""" + learned.load_ranker.cache_clear() + ranker = learned.load_ranker() + assert ranker is not None and ranker.features == FEATURES + learned.load_ranker.cache_clear() + monkeypatch.setenv("SEMBLE_LEARNED_RANKER", "0") + assert learned.load_ranker() is None + learned.load_ranker.cache_clear()