# How to deal with design spaces¶

## 1. How is a design space defined?¶

### 1.a. What is a design space made of?¶

A design space is defined by:

the number of the variables

the names of the variables

the sizes of the variables

the upper bounds of the variables (optional; by default: \(-\infty\))

the lower bounds of the variables (optional; by default: \(+\infty\))

the normalization policies of the variables:

bounded float variables are normalizable,

bounded interger variables are normalizable,

unbounded float variables are not normalizable,

unbounded integer variables are not normalizable.

Note

The normalized version of a given variable \(x\) is either \(\frac{x-lb_x}{ub_x-lb_x}\) or \(\frac{x}{ub_x-lb_x}\).

### 1.b. How is a design space implemented in GEMSEO?¶

Design space are implemented in GEMSEO through the `DesignSpace`

class.

### 1.c. What are the API functions in GEMSEO?¶

A design space can be created from the `create_design_space()`

and `read_design_space()`

API functions and then, enhanced by methods of the `DesignSpace`

class. It can be exported to a file by means of the `export_design_space()`

.

## 2. How to read a design space from a file?¶

### Case 1: the file contains a header line¶

Let’s consider the *design_space.txt* file containing the following lines:

```
name lower_bound value upper_bound type
x1 -1. 0. 1. float
x2 5. 6. 8. float
```

We can read this file by means of the `read_design_space()`

function API:

```
from gemseo.api import read_design_space
design_space = read_design_space('design_space.txt')
```

and print it:

```
print(design_space)
```

which results in:

```
Design Space:
+------+-------------+-------+-------------+-------+
| name | lower_bound | value | upper_bound | type |
+------+-------------+-------+-------------+-------+
| x1 | -1 | 0 | 1 | float |
| x2 | 5 | 6 | 8 | float |
+------+-------------+-------+-------------+-------+
```

### Case 2: the file does not contain a header line¶

Now, let’s consider the *design_space_without_header.txt* file containing the following lines:

```
x1 -1. 0. 1. float
x2 5. 6. 8. float
```

We can read this file by means of the `read_design_space()`

API function
with the list of labels as optional argument:

```
from gemseo.api import read_design_space
design_space = read_design_space(
"design_space_without_header.txt",
["name", "lower_bound", "value", "upper_bound", "type"],
)
```

and print it:

```
print(design_space)
```

which results in:

```
Design Space:
+------+-------------+-------+-------------+-------+
| name | lower_bound | value | upper_bound | type |
+------+-------------+-------+-------------+-------+
| x1 | -1 | 0 | 1 | float |
| x2 | 5 | 6 | 8 | float |
+------+-------------+-------+-------------+-------+
```

Warning

User must provide the following minimal fields in the file defining the design space:

`'name'`

,`'lower_bound'`

and`'upper_bound'`

.The inequality

`'lower_bound'`

<=`'name'`

<=`'upper_bound'`

must be satisfied.

Note

Available fields are

`'name'`

,`'lower_bound'`

,`'upper_bound'`

,`'value'`

and`'type'`

.The

`'value'`

field is optional. By default, it is set at`None`

.The

`'type'`

field is optional. By default, it is set at`float`

.Each dimension of a variable must be provided. E.g. when the

`'size'`

of`'x1'`

is 2:name lower_bound value upper_bound type x1 -1. 0. 1. float x1 -3. -1. 1. float x2 5. 6. 8. float

Note

Lower infinite bound is encoded

`-inf'`

or`'-Inf'`

.Upper infinite bound is encoded

`'inf'`

,`'Inf'`

,`'+inf'`

or`'+Inf'`

.

## 3. How to create a design space from scratch?¶

Let’s imagine that we want to build a design space with the following requirements:

*x1*is a one-dimensional unbounded float variable,*x2*is a one-dimensional unbounded integer variable,*x3*is a two-dimensional unbounded float variable,*x4*is a one-dimensional float variable with lower bound equal to 1,*x5*is a one-dimensional float variable with upper bound equal to 1,*x6*is a one-dimensional unbounded float variable,*x7*is a two-dimensional bounded integer variable with lower bound equal to -1, upper bound equal to 1 and current values to (0,1),

We can create this design space from scratch by means of the `create_design_space()`

API function and the `DesignSpace.add_variable()`

method of the `DesignSpace`

class:

```
from gemseo.api import create_design_space
from numpy import ones, array
design_space = create_design_space()
design_space.add_variable('x1')
design_space.add_variable('x2', var_type='integer')
design_space.add_variable('x3', size=2)
design_space.add_variable('x4', l_b=ones(1))
design_space.add_variable('x5', u_b=ones(1))
design_space.add_variable('x6', value=ones(1))
design_space.add_variable(
"x7", size=2, var_type="integer", value=array([0, 1]), l_b=-ones(2), u_b=ones(2)
)
```

and print it:

```
print(design_space)
```

which results in:

```
Design Space:
+------+-------------+-------+-------------+---------+
| name | lower_bound | value | upper_bound | type |
+------+-------------+-------+-------------+---------+
| x1 | -inf | None | inf | float |
| x2 | -inf | None | inf | integer |
| x3 | -inf | None | inf | float |
| x3 | -inf | None | inf | float |
| x4 | 1 | None | inf | float |
| x5 | -inf | None | 1 | float |
| x6 | -inf | 1 | inf | float |
| x7 | -1 | 0 | 1 | integer |
| x7 | -1 | 1 | 1 | integer |
+------+-------------+-------+-------------+---------+
```

Note

For a variable whose `'size'`

is greater than 1, each dimension of this variable is printed (e.g. `'x3'`

and `'x7'`

).

Note

We can get a list of the variable names with theirs indices by means of the `DesignSpace.get_indexed_variables_names()`

method:

```
indexed_variables_names = design_space.get_indexed_variables_names()
```

and `print(indexed_variables_names)`

:

```
['x1', 'x2', 'x3!0', 'x3!1', 'x4', 'x5', 'x6', 'x7!0', 'x7!1']
```

We see that the multidimensional variables have an index (here `'0'`

and `'1'`

) preceded by a `'!'`

separator.

## 4. How to get information about the design space?¶

### How to get the size of a design variable?¶

We can get the size of a variable by means of the `DesignSpace.get_size()`

method:

```
x3_size = design_space.get_size('x3')
```

and `print(x3_size)`

to see the result:

```
1
```

### How to get the type of a design variable?¶

We can get the type of a variable by means of the `DesignSpace.get_type()`

method:

```
x3_type = design_space.get_type('x3')
```

and `print(x3_type)`

to see the result:

```
['float']
```

### How to get the size of a lower or upper bound for a given variable?¶

We can get the lower and upper bounds of a variable by means of the `DesignSpace.get_lower_bound()`

and `DesignSpace.get_upper_bound()`

methods:

```
x3_lb = design_space.get_lower_bound('x3')
x3_ub = design_space.get_upper_bound('x3')
```

and `print(x3_lb, x3_ub)`

to see the result:

```
[-10.], [ 10.]
```

### How to get the size of a lower or upper bound for a set of given variables?¶

We can get the lower and upper bounds of a set of variables by means of the `DesignSpace.get_lower_bounds()`

and `DesignSpace.get_upper_bounds()`

methods:

```
x1x3_lb = design_space.get_lower_bounds(['x1', 'x3'])
x1x3_ub = design_space.get_upper_bounds(['x1', 'x3'])
```

and `print(x1x3_lb, x1x3_ub)`

to see the result:

```
[-10. -10.], [ 10. 10.]
```

### How to get the current array value of the design parameter vector?¶

We can get the current value of the design parameters by means of the `DesignSpace.get_lower_bounds()`

and `DesignSpace.get_current_x()`

method:

```
current_x = design_space.get_current_x
```

and `print(current_x)`

to see the result:

```
[ 3. 1. 1. 1.]
```

### How to get the current dictionary value of the design parameter vector?¶

We can get the current value of the design parameters with `dict`

format by means of the `DesignSpace.get_lower_bounds()`

and `DesignSpace.get_current_x_dict()`

method:

```
dict_current_x = design_space.get_current_x_dict
```

and `print(dict_current_x)`

to see the result:

```
{'x2': array([1.]), 'x3': array([1.]), 'x1': array([3.]), 'x6': array([1.])}
```

### How to get the normalized array value of the design parameter vector?¶

We can get the normalized current value of the design parameters by means of the `DesignSpace.get_lower_bounds()`

and `DesignSpace.get_current_x_normalized()`

method:

```
normalized_current_x = design_space.get_current_x_normalized
```

and `print(normalized_current_x)`

to see the result:

```
[ 0.65 1. 0.55 0.55]
```

### How to get the active bounds at the current design parameter vector or at a given one?¶

We can get the active bounds by means of the `DesignSpace.get_lower_bounds()`

and `DesignSpace.get_active_bounds()`

method, either at current parameter values:

```
active_at_current_x = design_space.get_active_bounds()
```

and `print(active_at_current_x)`

to see the result:

```
({'x2': array([False], dtype=bool), 'x3': array([False], dtype=bool), 'x1': array([False], dtype=bool), 'x6': array([False], dtype=bool)}, {'x2': array([False], dtype=bool), 'x3': array([False], dtype=bool), 'x1': array([False], dtype=bool), 'x6': array([False], dtype=bool)})
```

or at a given point:

```
active_at_given_point = design_space.get_active_bounds(array([1., 10, 1., 1.]))
```

and `print(active_at_given_point)`

to see the result:

## 5. How to modify a design space?¶

### How to remove a variable from a design space?¶

Let’s consider the previous design space and assume that we want to remove the `'x4'`

variable.

For that, we can use the `DesignSpace.remove_variable()`

method:

```
design_space.remove_variable('x4')
```

and `print(design_space)`

to see the result:

```
Design Space:
+------+-------------+-------+-------------+---------+
| name | lower_bound | value | upper_bound | type |
+------+-------------+-------+-------------+---------+
| x1 | -inf | None | inf | float |
| x2 | -inf | None | inf | integer |
| x3 | -inf | None | inf | float |
| x3 | -inf | None | inf | float |
| x5 | -inf | None | 1 | float |
| x6 | -inf | 1 | inf | float |
| x7 | -1 | 0 | 1 | integer |
| x7 | -1 | 1 | 1 | integer |
+------+-------------+-------+-------------+---------+
```

### How to filter the entries of a design space?¶

We can keep only a subset of variables, e.g. `'x1'`

, `'x2'`

, `'x3'`

and `'x6'`

, by means of the `gemseo.algos.design_space.DesignSpace.filter()`

method:

```
design_space.filter(['x1', 'x2', 'x3', 'x6']) # keep the x1, x2, x3 and x6 variables
```

and `print(design_space)`

to see the result:

```
Design Space:
+------+-------------+-------+-------------+---------+
| name | lower_bound | value | upper_bound | type |
+------+-------------+-------+-------------+---------+
| x1 | -inf | None | inf | float |
| x2 | -inf | None | inf | integer |
| x3 | -inf | None | inf | float |
| x3 | -inf | None | inf | float |
| x6 | -inf | 1 | inf | float |
+------+-------------+-------+-------------+---------+
```

We can also keep only a subset of components for a given variable, e.g. the first component of the variable `'x3'`

, by means of the `gemseo.algos.design_space.DesignSpace.filter_dim()`

method:

```
design_space.filer_dim('x3', [0]) # keep the first dimension of x3
```

and `print(design_space)`

to see the result:

```
Design Space:
+------+-------------+-------+-------------+---------+
| name | lower_bound | value | upper_bound | type |
+------+-------------+-------+-------------+---------+
| x1 | -inf | None | inf | float |
| x2 | -inf | None | inf | integer |
| x3 | -inf | None | inf | float |
| x6 | -inf | 1 | inf | float |
+------+-------------+-------+-------------+---------+
```

### How to modify the data values contained in a design space?¶

We can change the current values and bounds contained in a design space by means of the `DesignSpace.set_current_x()`

, `DesignSpace.set_current_variable()`

, `DesignSpace.set_lower_bound()`

and `DesignSpace.set_upper_bound()`

methods:

```
design_space.set_current_x(array([1., 1., 1., 1.]))
design_space.set_current_variable('x1', array([3.]))
design_space.set_lower_bound('x1', array([-10.]))
design_space.set_lower_bound('x2', array([-10.]))
design_space.set_lower_bound('x3', array([-10.]))
design_space.set_lower_bound('x6', array([-10.]))
design_space.set_upper_bound('x1', array([10.]))
design_space.set_upper_bound('x2', array([10.]))
design_space.set_upper_bound('x3', array([10.]))
design_space.set_upper_bound('x6', array([10.]))
```

and `print(design_space)`

to see the result:

```
Design Space:
+------+-------------+-------+-------------+---------+
| name | lower_bound | value | upper_bound | type |
+------+-------------+-------+-------------+---------+
| x1 | -10 | 3 | 10 | float |
| x2 | -10 | 1 | 10 | integer |
| x3 | -10 | 1 | 10 | float |
| x6 | -10 | 1 | 10 | float |
+------+-------------+-------+-------------+---------+
```

## 6. How to (un)normalize a parameter vector?¶

Let’s consider the parameter vector `x_vect = array([1.,10.,1.,1.])`

. We can normalize this vector by means of the `DesignSpace.normalize_vect()`

:

```
normalized_x_vect = design_space.normalize_vect(x_vect)
```

and `print(normalized_x_vect)`

:

```
[ 0.55 1. 0.55 0.55]
```

Conversely, we can unnormalize this normalized vector by means of the `DesignSpace.unnormalize_vect()`

:

```
unnormalized_x_vect = design_space.unnormalize_vect(x_vect)
```

```
[ 1. 10. 1. 1.]
```

Note

Both methods takes an optional argument denoted `'minus_lb'`

which is `True`

by default. If `True`

, the normalization of the normalizable variables is of the form `(x-lb_x)/(ub_x-lb_x)`

. Otherwise, it is of the form `x/(ub_x-lb_x)`

. Here, when `minus_lb`

is `False`

, the normalize parameter vector is:

```
[ 0.05 0.5 0.05 0.05]
```

## 7. How to cast design data?¶

### How to cast a design point from array to dict?¶

We can cast a design point from `array`

to `dict`

by means of the `DesignSpace.array_to_dict()`

method:

```
array_point = array([1, 2, 3, 4])
dict_point = design_space.array_to_dict(array_point)
```

and `print(dict_point)`

to see the result:

```
{'x2': array([2]), 'x3': array([3]), 'x1': array([1]), 'x6': array([4])}
```

### How to cast a design point from dict to array?¶

We can cast a design point from `dict`

to `array`

by means of the `DesignSpace.dict_to_array()`

method:

```
new_array_point = design_space.dict_to_array(dict_point)
```

and `print(new_array_point)`

to see the result:

```
[1, 2, 3, 4]
```

Note

An optional argument denoted

`'all_vars'`

, which is a boolean and set at`True`

by default, indicates if all design variables shall be in the`dict`

passed in argument.An optional argument denoted

`'all_var_list'`

, which is a list of string and set at`None`

by default, list all of the variables to consider. If`None`

, all design variables are considerd.

### How to cast the current value to complex?¶

We can cast the current value to complex by means of the `DesignSpace.to_complex()`

method:

```
print(design_space.get_current_x())
design_space.to_complex()
print(design_space.get_current_x())
```

and the successive printed messages are:

```
[ 3. 1. 1. 1.]
[ 3.+0.j 1.+0.j 1.+0.j 1.+0.j]
```

### How to cast the right component values of a vector to integer?¶

For a given vector where some components should be integer, it is possible to round them by means of the `DesignSpace.round_vect()`

method:

```
vector = array([1.3, 3.4,3.6, -1.4])
rounded_vector = design_space.round_vect(vector)
```

and `print(rounded_vector)`

to see the result:

```
[ 1.3 3. 3.6 -1.4]
```

## 8. How to test if the current value is defined?¶

We can test if the design parameter set has a current `'value'`

by means of the `DesignSpace.has_current_x()`

:

```
print(design_space.has_current_x())
```

which results in:

```
True
```

Note

The result returned by `DesignSpace.has_current_x()`

is `False`

as long as at least one component of one variable is `None`

.

## 9. How to project a point into bounds?¶

Sometimes, components of a design vector are greater than the upper bounds or lower than the upper bounds. For that, it is possible to project the vector into the bounds by means of the `DesignSpace.project_into_bounds()`

:

```
point = array([1.,3,-15.,23.])
p_point = design_space.project_into_bounds(point)
```

and `print(p_point)`

to see the result:

```
[ 1. 3. -10. 10.]
```

## 10. How to export a design space to a file?¶

When the design space is created, it is possible to export it by means of the `export_design_space()`

API function with arguments:

`design_space`

: design space`output_file`

: output file path`export_hdf`

: export to a hdf file (True, default) or a txt file (False)`fields`

: list of fields to export, by default all`append`

: if`True`

, appends the data in the file`table_options`

: dictionary of options for the`PrettyTable`

For example:

```
from gemseo.api import export_design_space
export_design_space(design_space, 'new_design_space.txt')
```