Skip to content

Commit

Permalink
folder structure
Browse files Browse the repository at this point in the history
Signed-off-by: lc3267 <[email protected]>
  • Loading branch information
lc3267 committed Oct 14, 2024
1 parent eccf35e commit 982bec0
Show file tree
Hide file tree
Showing 50 changed files with 933 additions and 686 deletions.
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ $$ $$$$$$$$$$$$$$$$$$$$$$$ $$
$$$ $$$$$ $$$ \__> \/ \/ \/
```

# HEPQPR.Qallse
# qallse

The [HEPQPR](https://sites.google.com/lbl.gov/hep-qpr).Qallse project encodes the HEP (ATLAS) pattern recognition problem into a QUBO and solves it using a D-Wave or other classical QUBO libraries (qbsolv, neal).

Expand Down Expand Up @@ -67,7 +67,7 @@ I am available for any question (email or Github issue is fine) and would be gla

### Current models

Different versions of the model building (i.e. QUBO generation) exist. They are organised into a class hierarchy starting at the abstract class `hepqpr.qallse.QallseBase`:
Different versions of the model building (i.e. QUBO generation) exist. They are organised into a class hierarchy starting at the abstract class `qallse.QallseBase`:

* `.qallse.Qallse`: basic implementation, using constant bias weights.
* `.qallse_mp.QallseMp`: adds a filtering step during triplets generation, which greatly limits the size of the QUBO;
Expand Down Expand Up @@ -151,18 +151,18 @@ Dataset written in /tmp/mini/ds05/event000001000* (seed=376778465, num. tracks=4
# build the model
> qallse -i /tmp/mini/ds05/event000001000-hits.csv -o /tmp/mini build
INPUT -- precision (%): 0.8610, recall (%): 99.5885, missing: 1
2019-01-29T09:54:05.691 [hepqpr.qallse.qallse_d0 INFO ] created 15341 doublets.
2019-01-29T09:54:06.995 [hepqpr.qallse.qallse_d0 INFO ] created 3160 triplets.
2019-01-29T09:54:07.022 [hepqpr.qallse.qallse_d0 INFO ] created 686 quadruplets.
2019-01-29T09:54:07.022 [hepqpr.qallse.qallse_d0 INFO ] Model built in 3.12s. doublets: 15341/0, triplets: 3160/0, quadruplets: 686
2019-01-29T09:54:07.030 [hepqpr.qallse.qallse_d0 INFO ] MaxPath done in 0.02s. doublets: 544, triplets: 628, quadruplets: 638 (dropped 48)
2019-01-29T09:54:07.073 [hepqpr.qallse.qallse_d0 INFO ] Qubo generated in 0.07s. Size: 2877. Vars: 628, excl. couplers: 1611, incl. couplers: 638
2019-01-29T09:54:05.691 [qallse.qallse_d0 INFO ] created 15341 doublets.
2019-01-29T09:54:06.995 [qallse.qallse_d0 INFO ] created 3160 triplets.
2019-01-29T09:54:07.022 [qallse.qallse_d0 INFO ] created 686 quadruplets.
2019-01-29T09:54:07.022 [qallse.qallse_d0 INFO ] Model built in 3.12s. doublets: 15341/0, triplets: 3160/0, quadruplets: 686
2019-01-29T09:54:07.030 [qallse.qallse_d0 INFO ] MaxPath done in 0.02s. doublets: 544, triplets: 628, quadruplets: 638 (dropped 48)
2019-01-29T09:54:07.073 [qallse.qallse_d0 INFO ] Qubo generated in 0.07s. Size: 2877. Vars: 628, excl. couplers: 1611, incl. couplers: 638
Wrote qubo to /tmp/mini/qubo.pickle

# solve using neal
> qallse -i /tmp/mini/ds05/event000001000-hits.csv -o /tmp/mini neal
2019-01-29T09:56:51.207 [hepqpr.qallse.cli.func INFO ] QUBO of size 2877 sampled in 0.14s (NEAL, seed=1615186406).
2019-01-29T09:56:51.619 [hepqpr.qallse.track_recreater INFO ] Found 0 conflicting doublets
2019-01-29T09:56:51.207 [qallse.cli.func INFO ] QUBO of size 2877 sampled in 0.14s (NEAL, seed=1615186406).
2019-01-29T09:56:51.619 [qallse.track_recreater INFO ] Found 0 conflicting doublets
SAMPLE -- energy: -165.7110, ideal: -163.1879 (diff: -2.523028)
best sample occurrence: 1/10
SCORE -- precision (%): 99.1769547325103, recall (%): 99.1769547325103, missing: 2
Expand Down Expand Up @@ -203,7 +203,7 @@ qallse -i /tmp/mini/ds05/event000001000-hits.csv -o /tmp/mini qbsolv \

The `examples` directory contains some examples on how to do everything from scripts instead of using the commandline.

Other very useful functions are available in `hepqpr.qallse.cli.func` and pretty self-explanatory.
Other very useful functions are available in `qallse.cli.func` and pretty self-explanatory.


### Running from an IPython notebook
Expand All @@ -229,7 +229,7 @@ See the notebook example for more information.

### The plotting module

You can use `hepqpr.qallse.plotting` for plotting doublets and tracks easily.
You can use `qallse.plotting` for plotting doublets and tracks easily.

__Jupyter__: if you are running in a notebook, you need to tell the module so by calling `set_notebook_mode()`.

Expand All @@ -238,9 +238,9 @@ The methods take a `DataWrapper` and a list of xplets (an xplet is here a list o
Typical usage:

```python
from hepqpr.qallse import DataWrapper
from hepqpr.qallse.cli.func import process_response
from hepqpr.qallse.plotting import *
from qallse import DataWrapper
from qallse.cli.func import process_response
from qallse.plotting import *

set_notebook_mode() # if running inside a notebook

Expand Down
27 changes: 16 additions & 11 deletions examples/build_qubo.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,45 @@
import sys
import logging

from hepqpr.qallse import *
from hepqpr.qallse import dumper
from qallse import *
from qallse import dumper

# ==== BUILD CONFIG

loglevel = logging.DEBUG

input_path = '/tmp/ez-0.1_hpt-1.0/event000001000-hits.csv' # TODO change it !
output_path = '/tmp' # TODO change it
input_path = "/tmp/ez-0.1_hpt-1.0/event000001000-hits.csv" # TODO change it !
output_path = "/tmp" # TODO change it

model_class = QallseD0 # model class to use
extra_config = dict() # model config

dump_config = dict(
output_path='/tmp',
prefix='',
xplets_kwargs=dict(format='json', indent=3), # use json (vs "pickle") and indent the output
qubo_kwargs=dict(w_marker=None, c_marker=None) # save the real coefficients VS generic placeholders
output_path="/tmp",
prefix="",
xplets_kwargs=dict(
format="json", indent=3
), # use json (vs "pickle") and indent the output
qubo_kwargs=dict(
w_marker=None, c_marker=None
), # save the real coefficients VS generic placeholders
)

# ==== configure logging

logging.basicConfig(
stream=sys.stderr,
format="%(asctime)s.%(msecs)03d [%(name)-15s %(levelname)-5s] %(message)s",
datefmt='%Y-%m-%dT%H:%M:%S')
datefmt="%Y-%m-%dT%H:%M:%S",
)

logging.getLogger('hepqpr').setLevel(loglevel)
logging.getLogger("hepqpr").setLevel(loglevel)

# ==== build model

# load data
dw = DataWrapper.from_path(input_path)
doublets = pd.read_csv(input_path.replace('-hits.csv', '-doublets.csv'))
doublets = pd.read_csv(input_path.replace("-hits.csv", "-doublets.csv"))

# build model
model = model_class(dw, **extra_config)
Expand Down
23 changes: 13 additions & 10 deletions examples/sample_qubo_neal.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@
import pickle
from os.path import join as path_join

from hepqpr.qallse import *
from qallse import *
from neal import SimulatedAnnealingSampler

# ==== RUN CONFIG

loglevel = logging.DEBUG

input_path = '/tmp/ez-0.1_hpt-1.0/event000001000-hits.csv' # TODO change it !
qubo_path = '/tmp' # TODO change it
input_path = "/tmp/ez-0.1_hpt-1.0/event000001000-hits.csv" # TODO change it !
qubo_path = "/tmp" # TODO change it

sampler = SimulatedAnnealingSampler()

Expand All @@ -30,15 +30,16 @@
logging.basicConfig(
stream=sys.stderr,
format="%(asctime)s.%(msecs)03d [%(name)-15s %(levelname)-5s] %(message)s",
datefmt='%Y-%m-%dT%H:%M:%S')
datefmt="%Y-%m-%dT%H:%M:%S",
)

logging.getLogger('hepqpr').setLevel(loglevel)
logging.getLogger("hepqpr").setLevel(loglevel)

# ==== build model

# load data
dw = DataWrapper.from_path(input_path)
with open(path_join(qubo_path, 'qubo.pickle'), 'rb') as f:
with open(path_join(qubo_path, "qubo.pickle"), "rb") as f:
Q = pickle.load(f)

# sample qubo
Expand All @@ -57,8 +58,10 @@
trackml_score = dw.compute_trackml_score(final_tracks)

# print stats
print(f'SAMPLE -- energy: {en:.4f}, ideal: {en0:.4f} (diff: {en-en0:.6f})')
print(f' best sample occurrence: {occs[0]}/{occs.sum()}')
print(f"SAMPLE -- energy: {en:.4f}, ideal: {en0:.4f} (diff: {en-en0:.6f})")
print(f" best sample occurrence: {occs[0]}/{occs.sum()}")

print(f'SCORE -- precision (%): {p * 100}, recall (%): {r * 100}, missing: {len(ms)}')
print(f' tracks found: {len(final_tracks)}, trackml score (%): {trackml_score * 100}')
print(f"SCORE -- precision (%): {p * 100}, recall (%): {r * 100}, missing: {len(ms)}")
print(
f" tracks found: {len(final_tracks)}, trackml score (%): {trackml_score * 100}"
)
33 changes: 19 additions & 14 deletions examples/sample_qubo_qbsolv.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@
"""

raise NotImplementedError("Dwave's QBsolv is deprecated as of 2022. " \
"The hybrid Dwave solver requires refactoring.")
raise NotImplementedError(
"Dwave's QBsolv is deprecated as of 2022. "
"The hybrid Dwave solver requires refactoring."
)

import sys
import logging
import pickle
from os.path import join as path_join

from hepqpr.qallse import *
from hepqpr.qallse.other.stdout_redirect import capture_stdout
from qallse import *
from qallse.other.stdout_redirect import capture_stdout

from dwave_qbsolv import QBSolv

Expand All @@ -26,9 +28,9 @@

loglevel = logging.DEBUG

input_path = '/tmp/ez-0.1_hpt-1.0/event000001000-hits.csv' # TODO change it !
qubo_path = '/tmp' # TODO change it
logfile = '/tmp/qbsolv.log' # try to run parse_qbsolv -i /tmp/qbsolv.log afterwards :)
input_path = "/tmp/ez-0.1_hpt-1.0/event000001000-hits.csv" # TODO change it !
qubo_path = "/tmp" # TODO change it
logfile = "/tmp/qbsolv.log" # try to run parse_qbsolv -i /tmp/qbsolv.log afterwards :)

sampler = QBSolv()
sampler_args = dict(
Expand All @@ -42,15 +44,16 @@
logging.basicConfig(
stream=sys.stderr,
format="%(asctime)s.%(msecs)03d [%(name)-15s %(levelname)-5s] %(message)s",
datefmt='%Y-%m-%dT%H:%M:%S')
datefmt="%Y-%m-%dT%H:%M:%S",
)

logging.getLogger('hepqpr').setLevel(loglevel)
logging.getLogger("hepqpr").setLevel(loglevel)

# ==== build model

# load data
dw = DataWrapper.from_path(input_path)
with open(path_join(qubo_path, 'qubo.pickle'), 'rb') as f:
with open(path_join(qubo_path, "qubo.pickle"), "rb") as f:
Q = pickle.load(f)

# sample qubo
Expand All @@ -70,8 +73,10 @@
trackml_score = dw.compute_trackml_score(final_tracks)

# print stats
print(f'SAMPLE -- energy: {en:.4f}, ideal: {en0:.4f} (diff: {en-en0:.6f})')
print(f' best sample occurrence: {occs[0]}/{occs.sum()}')
print(f"SAMPLE -- energy: {en:.4f}, ideal: {en0:.4f} (diff: {en-en0:.6f})")
print(f" best sample occurrence: {occs[0]}/{occs.sum()}")

print(f'SCORE -- precision (%): {p * 100}, recall (%): {r * 100}, missing: {len(ms)}')
print(f' tracks found: {len(final_tracks)}, trackml score (%): {trackml_score * 100}')
print(f"SCORE -- precision (%): {p * 100}, recall (%): {r * 100}, missing: {len(ms)}")
print(
f" tracks found: {len(final_tracks)}, trackml score (%): {trackml_score * 100}"
)
90 changes: 45 additions & 45 deletions notebooks/simple-run-example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook runs a `Qallse` model in simulation mode and shows how to simply visualize the results using utilities defined in module `hepqpr.qallse.plotting`."
"This notebook runs a `Qallse` model in simulation mode and shows how to simply visualize the results using utilities defined in module `qallse.plotting`."
]
},
{
Expand Down Expand Up @@ -34,9 +34,9 @@
"import pandas as pd\n",
"import numpy as np\n",
"\n",
"from hepqpr.qallse.plotting import *\n",
"from hepqpr.qallse import *\n",
"from hepqpr.qallse.dsmaker import create_dataset\n",
"from qallse.plotting import *\n",
"from qallse import *\n",
"from qallse.dsmaker import create_dataset\n",
"\n",
"# initialise the plotting module in \"notebook\" mode\n",
"set_notebook_mode()\n",
Expand Down Expand Up @@ -102,17 +102,17 @@
"name": "stderr",
"output_type": "stream",
"text": [
"17:46:22.850 DEBUG hepqpr.qallse.dsmaker.dsmaker: Loaded 120939 hits from /Users/lin/git/quantum-annealing-project/project-2/src/hepqpr/qallse/dsmaker/data/event000001000.\n",
"17:46:22.873 DEBUG hepqpr.qallse.dsmaker.dsmaker: Filtered hits from barrel. Remaining hits: 65518.\n",
"17:46:22.914 DEBUG hepqpr.qallse.dsmaker.dsmaker: Dropped double hits. Remaining hits: 55446.\n",
"17:46:22.935 DEBUG hepqpr.qallse.dsmaker.dsmaker: High Pt hits: 32302/524\n",
"17:46:22.967 DEBUG hepqpr.qallse.dsmaker.dsmaker: num_hits=524\n",
"17:46:22.967 DEBUG hepqpr.qallse.dsmaker.dsmaker: num_tracks=81\n",
"17:46:22.968 DEBUG hepqpr.qallse.dsmaker.dsmaker: num_important_tracks=4\n",
"17:46:22.968 DEBUG hepqpr.qallse.dsmaker.dsmaker: num_noise=130\n",
"17:46:22.969 DEBUG hepqpr.qallse.dsmaker.dsmaker: random_seed=1547862382\n",
"17:46:22.969 DEBUG hepqpr.qallse.dsmaker.dsmaker: time=2019-01-18T17:46:22.967102\n",
"17:46:23.219 INFO hepqpr.qallse.dsmaker.dsmaker: Doublets (len=1352) generated in f/var/folders/qp/grrqv98s1c37f8bxtkblfpcr0000gn/T/tmpra3o223v/ez-0.01_hpt-1.0/event000001000.\n"
"17:46:22.850 DEBUG qallse.dsmaker.dsmaker: Loaded 120939 hits from /Users/lin/git/quantum-annealing-project/project-2/src/hepqpr/qallse/dsmaker/data/event000001000.\n",
"17:46:22.873 DEBUG qallse.dsmaker.dsmaker: Filtered hits from barrel. Remaining hits: 65518.\n",
"17:46:22.914 DEBUG qallse.dsmaker.dsmaker: Dropped double hits. Remaining hits: 55446.\n",
"17:46:22.935 DEBUG qallse.dsmaker.dsmaker: High Pt hits: 32302/524\n",
"17:46:22.967 DEBUG qallse.dsmaker.dsmaker: num_hits=524\n",
"17:46:22.967 DEBUG qallse.dsmaker.dsmaker: num_tracks=81\n",
"17:46:22.968 DEBUG qallse.dsmaker.dsmaker: num_important_tracks=4\n",
"17:46:22.968 DEBUG qallse.dsmaker.dsmaker: num_noise=130\n",
"17:46:22.969 DEBUG qallse.dsmaker.dsmaker: random_seed=1547862382\n",
"17:46:22.969 DEBUG qallse.dsmaker.dsmaker: time=2019-01-18T17:46:22.967102\n",
"17:46:23.219 INFO qallse.dsmaker.dsmaker: Doublets (len=1352) generated in f/var/folders/qp/grrqv98s1c37f8bxtkblfpcr0000gn/T/tmpra3o223v/ez-0.01_hpt-1.0/event000001000.\n"
]
}
],
Expand Down Expand Up @@ -217,34 +217,34 @@
"name": "stderr",
"output_type": "stream",
"text": [
"17:46:33.161 DEBUG hepqpr.qallse.qallse_d0: using config:\n",
"17:46:33.162 DEBUG hepqpr.qallse.qallse_d0: beamspot_center: (0, 0, 0)\n",
"17:46:33.163 DEBUG hepqpr.qallse.qallse_d0: beamspot_width: 27.5\n",
"17:46:33.163 DEBUG hepqpr.qallse.qallse_d0: cheat: False\n",
"17:46:33.164 DEBUG hepqpr.qallse.qallse_d0: d0_denom: 3.0\n",
"17:46:33.165 DEBUG hepqpr.qallse.qallse_d0: d0_factor: 0.5\n",
"17:46:33.165 DEBUG hepqpr.qallse.qallse_d0: max_layer_span: 2\n",
"17:46:33.166 DEBUG hepqpr.qallse.qallse_d0: min_qplet_path: 2\n",
"17:46:33.166 DEBUG hepqpr.qallse.qallse_d0: num_multiplier: -1\n",
"17:46:33.167 DEBUG hepqpr.qallse.qallse_d0: qplet_max_dcurv: 0.0001\n",
"17:46:33.167 DEBUG hepqpr.qallse.qallse_d0: qplet_max_strength: -0.2\n",
"17:46:33.168 DEBUG hepqpr.qallse.qallse_d0: qubo_bias_weight: 0\n",
"17:46:33.168 DEBUG hepqpr.qallse.qallse_d0: qubo_conflict_strength: 1\n",
"17:46:33.169 DEBUG hepqpr.qallse.qallse_d0: rz_power: 1\n",
"17:46:33.169 DEBUG hepqpr.qallse.qallse_d0: strength_bounds: None\n",
"17:46:33.169 DEBUG hepqpr.qallse.qallse_d0: tplet_max_curv: 0.0008\n",
"17:46:33.170 DEBUG hepqpr.qallse.qallse_d0: tplet_max_drz: 0.1\n",
"17:46:33.170 DEBUG hepqpr.qallse.qallse_d0: volayer_power: 2\n",
"17:46:33.171 DEBUG hepqpr.qallse.qallse_d0: xy_power: 1\n",
"17:46:33.171 DEBUG hepqpr.qallse.qallse_d0: xy_relative_strength: 0.5\n",
"17:46:33.172 DEBUG hepqpr.qallse.qallse_d0: z0_denom: 1.0\n",
"17:46:33.172 DEBUG hepqpr.qallse.qallse_d0: z0_factor: 0.1\n",
"17:46:33.238 INFO hepqpr.qallse.qallse_d0: created 810 doublets.\n",
"17:46:33.263 INFO hepqpr.qallse.qallse_d0: created 267 triplets.\n",
"17:46:33.268 INFO hepqpr.qallse.qallse_d0: created 201 quadruplets.\n",
"17:46:33.268 INFO hepqpr.qallse.qallse_d0: Model built in 0.08s. doublets: 0, triplets: 0, quadruplets: 201\n",
"17:46:33.272 INFO hepqpr.qallse.qallse_d0: MaxPath done in 0.01s. doublets: 159, triplets: 187, quadruplets: 192 (dropped 9)\n",
"17:46:33.292 INFO hepqpr.qallse.qallse_d0: Qubo generated in 0.03s. Size: 852. Vars: 187, excl. couplers: 473, incl. couplers: 192\n"
"17:46:33.161 DEBUG qallse.qallse_d0: using config:\n",
"17:46:33.162 DEBUG qallse.qallse_d0: beamspot_center: (0, 0, 0)\n",
"17:46:33.163 DEBUG qallse.qallse_d0: beamspot_width: 27.5\n",
"17:46:33.163 DEBUG qallse.qallse_d0: cheat: False\n",
"17:46:33.164 DEBUG qallse.qallse_d0: d0_denom: 3.0\n",
"17:46:33.165 DEBUG qallse.qallse_d0: d0_factor: 0.5\n",
"17:46:33.165 DEBUG qallse.qallse_d0: max_layer_span: 2\n",
"17:46:33.166 DEBUG qallse.qallse_d0: min_qplet_path: 2\n",
"17:46:33.166 DEBUG qallse.qallse_d0: num_multiplier: -1\n",
"17:46:33.167 DEBUG qallse.qallse_d0: qplet_max_dcurv: 0.0001\n",
"17:46:33.167 DEBUG qallse.qallse_d0: qplet_max_strength: -0.2\n",
"17:46:33.168 DEBUG qallse.qallse_d0: qubo_bias_weight: 0\n",
"17:46:33.168 DEBUG qallse.qallse_d0: qubo_conflict_strength: 1\n",
"17:46:33.169 DEBUG qallse.qallse_d0: rz_power: 1\n",
"17:46:33.169 DEBUG qallse.qallse_d0: strength_bounds: None\n",
"17:46:33.169 DEBUG qallse.qallse_d0: tplet_max_curv: 0.0008\n",
"17:46:33.170 DEBUG qallse.qallse_d0: tplet_max_drz: 0.1\n",
"17:46:33.170 DEBUG qallse.qallse_d0: volayer_power: 2\n",
"17:46:33.171 DEBUG qallse.qallse_d0: xy_power: 1\n",
"17:46:33.171 DEBUG qallse.qallse_d0: xy_relative_strength: 0.5\n",
"17:46:33.172 DEBUG qallse.qallse_d0: z0_denom: 1.0\n",
"17:46:33.172 DEBUG qallse.qallse_d0: z0_factor: 0.1\n",
"17:46:33.238 INFO qallse.qallse_d0: created 810 doublets.\n",
"17:46:33.263 INFO qallse.qallse_d0: created 267 triplets.\n",
"17:46:33.268 INFO qallse.qallse_d0: created 201 quadruplets.\n",
"17:46:33.268 INFO qallse.qallse_d0: Model built in 0.08s. doublets: 0, triplets: 0, quadruplets: 201\n",
"17:46:33.272 INFO qallse.qallse_d0: MaxPath done in 0.01s. doublets: 159, triplets: 187, quadruplets: 192 (dropped 9)\n",
"17:46:33.292 INFO qallse.qallse_d0: Qubo generated in 0.03s. Size: 852. Vars: 187, excl. couplers: 473, incl. couplers: 192\n"
]
},
{
Expand Down Expand Up @@ -284,7 +284,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"17:46:38.267 INFO hepqpr.qallse.qallse_d0: QUBO of size 852 sampled in 0.76s (seed 2025012979).\n"
"17:46:38.267 INFO qallse.qallse_d0: QUBO of size 852 sampled in 0.76s (seed 2025012979).\n"
]
},
{
Expand Down Expand Up @@ -318,7 +318,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"17:46:40.892 INFO hepqpr.qallse.track_recreater: Found 0 conflicting doublets\n"
"17:46:40.892 INFO qallse.track_recreater: Found 0 conflicting doublets\n"
]
}
],
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
def main():
from hepqpr.qallse.seeding.main import cli
from qallse.cli.entrypoints import cli

cli()


if __name__ == "__main__":
main()
Loading

0 comments on commit 982bec0

Please sign in to comment.