Repository: PennyLaneAI/pennylane

Issue:
[BUG] `qml.data.load()` fails when using 'full' parameter value
### Expected behavior

`qml.data.load('qspin',sysname='Heisenberg',periodicity='open',lattice='full',layout='2x2')`
Should return the Heisenberg dataset corresponding to the `open` periodicity, `rectangular` lattice, and `2x2` layout.

### Actual behavior

`qml.data.load('qspin',sysname='Heisenberg',periodicity='open',lattice='full',layout='2x2')`

Raises `ValueError: layout value of '2x2' is not available. Available values are ['1x16', '1x4', '1x8']`

### Additional information

_No response_

### Source code

```shell
qml.data.load('qspin',sysname='Heisenberg',periodicity='open',lattice='full',layout='1x4') # works

qml.data.load('qspin',sysname='Heisenberg',periodicity='open',lattice='full',layout='2x2') # fails
```


### Tracebacks

_No response_

### System information

```shell
Name: PennyLane
Version: 0.31.0.dev0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: https://github.com/XanaduAI/pennylane
Author: 
Author-email: 
License: Apache License 2.0
Location: .venv/lib/python3.8/site-packages
Editable project location: 
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml
Required-by: PennyLane-Lightning

Platform info:           Linux-5.15.0-73-generic-x86_64-with-glibc2.29
Python version:          3.8.10
Numpy version:           1.23.5
Scipy version:           1.10.1
Installed devices:
- default.gaussian (PennyLane-0.31.0.dev0)
- default.mixed (PennyLane-0.31.0.dev0)
- default.qubit (PennyLane-0.31.0.dev0)
- default.qubit.autograd (PennyLane-0.31.0.dev0)
- default.qubit.jax (PennyLane-0.31.0.dev0)
- default.qubit.tf (PennyLane-0.31.0.dev0)
- default.qubit.torch (PennyLane-0.31.0.dev0)
- default.qutrit (PennyLane-0.31.0.dev0)
- null.qubit (PennyLane-0.31.0.dev0)
- lightning.qubit (PennyLane-Lightning-0.30.0)
```


### Existing GitHub issues

- [X] I have searched existing GitHub issues to make sure the issue does not already exist.

Discussion:
github-actions[bot]: Hello. You may have forgotten to update the changelog!
Please edit [`doc/releases/changelog-dev.md`](/PennyLaneAI/pennylane/blob/master/doc/releases/changelog-dev.md) with:
* A one-to-two sentence description of the change. You may include a small working example for new features.
* A link back to this PR.
* Your name (or GitHub username) in the contributors section.
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/4663?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
All modified lines are covered by tests :white_check_mark:
> Comparison is base [(`2086ce8`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/2086ce8c1aac44efee8df857a5090b88c428f557?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) 99.63% compared to head [(`6a149ef`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/4663?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) 99.63%.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##           master    #4663   +/-   ##
=======================================
  Coverage   99.63%   99.63%           
=======================================
  Files         376      376           
  Lines       33663    33668    +5     
=======================================
+ Hits        33539    33544    +5     
  Misses        124      124           
```


| [Files](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/4663?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | Coverage Δ | |
|---|---|---|
| [pennylane/data/data\_manager/foldermap.py](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/4663?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2RhdGEvZGF0YV9tYW5hZ2VyL2ZvbGRlcm1hcC5weQ==) | `100.00% <100.00%> (ø)` | |


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/4663?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).

brownj85: > if one what is removed? and which 3 will be returned? I'm not entirely sure what the expected behaviour is there.

So before this PR, if `H2_CC-PVDZ_0.7` was removed from the datasets bucket (and the foldermap), calling
`qml.data.load('qchem', molname='H2', basis=['STO-3G', 'CC-PVDZ'], bondlength=['0.5', '0.7'])` would cause an exception, because one of the requested parameter combinations doesn't exist. After this PR it'll return the other 3 datasets without an exception. An exception is only raised if **none** of the requested parameter combinations exist.

There's not really an 'expected' behaviour here (afaik) so we're not breaking any promises.


Patch:
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index 1ac65dd07..b904b6e4a 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -210,6 +210,9 @@
   still a `_qfunc_output` property on `QNode` instances.
   [(#4651)](https://github.com/PennyLaneAI/pennylane/pull/4651)
 
+* `qml.data.load` properly handles parameters that come after `'full'`
+  [(#4663)](https://github.com/PennyLaneAI/pennylane/pull/4663)
+
 * The `qml.jordan_wigner` function has been modified to optionally remove the imaginary components
   of the computed qubit operator, if imaginary components are smaller than a threshold. 
   [(#4639)](https://github.com/PennyLaneAI/pennylane/pull/4639)
diff --git a/pennylane/data/data_manager/foldermap.py b/pennylane/data/data_manager/foldermap.py
index 9080535e8..bf4c0cde4 100644
--- a/pennylane/data/data_manager/foldermap.py
+++ b/pennylane/data/data_manager/foldermap.py
@@ -119,6 +119,7 @@ class FolderMapView(typing.Mapping[str, Union["FolderMapView", DataPath]]):
 
             while curr:
                 curr_description, curr_level = curr.pop()
+
                 if param_arg == ParamArg.FULL:
                     next_params = curr_level
                 elif param_arg == ParamArg.DEFAULT:
@@ -131,18 +132,29 @@ class FolderMapView(typing.Mapping[str, Union["FolderMapView", DataPath]]):
                 else:
                     next_params = param_arg
 
-                try:
-                    todo.extend(
+                for next_param in next_params:
+                    try:
+                        fmap_next = curr_level[next_param]
+                    except KeyError:
+                        continue
+
+                    todo.append(
                         (
                             Description((*curr_description.items(), (param_name, next_param))),
-                            curr_level[next_param],
+                            fmap_next,
                         )
-                        for next_param in next_params
                     )
-                except KeyError as exc:
-                    raise ValueError(
-                        f"{param_name} '{exc.args[0]}' is not available. Available values are: {list(curr_level)}"
-                    ) from exc
+
+            if len(todo) == 0:
+                # None of the parameters matched
+                param_arg_repr = (
+                    repr([param_arg])
+                    if isinstance(param_arg, (str, ParamArg))
+                    else repr(list(param_arg))
+                )
+                raise ValueError(
+                    f"{param_name} value(s) {param_arg_repr} are not available. Available values are: {list(curr_level)}"
+                )
 
             curr, todo = todo, curr
 


Test patch:
diff --git a/tests/data/data_manager/test_foldermap.py b/tests/data/data_manager/test_foldermap.py
index 2bfa56e60..8b5b21c88 100644
--- a/tests/data/data_manager/test_foldermap.py
+++ b/tests/data/data_manager/test_foldermap.py
@@ -15,6 +15,8 @@
 Tests for the :class:`pennylane.data.data_manger.FolderMapView` class.
 """
 
+import re
+
 import pytest
 
 from pennylane.data.data_manager import DEFAULT, FULL, DataPath
@@ -125,6 +127,38 @@ class TestFolderMapView:
                     ),
                 ],
             ),
+            (
+                {"missing_default": DEFAULT, "molname": "O2", "basis": FULL, "bondlength": ["0.6"]},
+                [
+                    (
+                        {"molname": "O2", "basis": "STO-3G", "bondlength": "0.6"},
+                        "qchem/O2/STO-3G/0.6.h5",
+                    ),
+                ],
+            ),
+            (
+                {
+                    "missing_default": DEFAULT,
+                    "molname": "O2",
+                    "basis": FULL,
+                    "bondlength": ["0.6", "200"],
+                },
+                [
+                    (
+                        {"molname": "O2", "basis": "STO-3G", "bondlength": "0.6"},
+                        "qchem/O2/STO-3G/0.6.h5",
+                    ),
+                ],
+            ),
+            (
+                {"missing_default": FULL, "molname": "O2", "bondlength": ["0.6"]},
+                [
+                    (
+                        {"molname": "O2", "basis": "STO-3G", "bondlength": "0.6"},
+                        "qchem/O2/STO-3G/0.6.h5",
+                    ),
+                ],
+            ),
         ],
     )
     def test_find(self, foldermap, kwds, expect):  # pylint: disable=redefined-outer-name
@@ -155,14 +189,36 @@ class TestFolderMapView:
         with pytest.raises(ValueError, match="No default available for parameter 'molname'"):
             FolderMapView(FOLDERMAP).find("qchem")
 
-    def test_find_invalid_parameter(self):
+    @pytest.mark.parametrize(
+        "arg, error_fmt", [("Z3", repr(["Z3"])), (("Z3", "Z4"), repr(["Z3", "Z4"]))]
+    )
+    def test_find_invalid_parameter(self, arg, error_fmt):
         """Test that a ValueError is raised when a parameter provided
         does not exist."""
 
         with pytest.raises(
-            ValueError, match=r"molname 'Z3' is not available. Available values are: \['O2', 'H2'\]"
+            ValueError,
+            match=re.escape(
+                f"molname value(s) {error_fmt} are not available. Available values are: ['O2', 'H2']"
+            ),
         ):
-            FolderMapView(FOLDERMAP).find("qchem", molname="Z3")
+            FolderMapView(FOLDERMAP).find("qchem", molname=arg)
+
+    @pytest.mark.parametrize("basis", [FULL, DEFAULT])
+    def test_find_invalid_parameters_after_full_default(self, basis):
+        """Test that a ValueError is raised when a parameter provided
+        does not exist, after a 'full' or 'default' parameter has been provided for a
+        higher-priority parameter."""
+
+        with pytest.raises(
+            ValueError,
+            match=(
+                r"bondlength value\(s\) \['0.20', '200'\] are not available. Available values are: \['0.5', '0.6'\]"
+            ),
+        ):
+            FolderMapView(FOLDERMAP).find(
+                "qchem", molname="O2", basis=basis, bondlength=["0.20", "200"]
+            )
 
     @pytest.mark.parametrize(
         "init, key, expect",