MATLAB object representation in HDF5 - matlab

Is it possible to retrieve object properties that were saved in MATLAB with -v7.3 in Python?
For example, take this class:
classdef TestClass < handle
properties
Name = 'Nobody';
Value = 42;
end
methods
function this = TestClass(name, value)
if nargin > 0
this.Name = name;
end
if nargin > 1
this.Value = value;
end
end
function doSomething(this)
fprintf('My name is â%sâ and my value is â%dâ.\n', this.Name, this.Value);
end
end
end
and create and save a few objects:
a=TestClass('Theo', 17)
b=TestClass
c=[a,b]
d={a,b}
save('testClassF.mat', 'a', 'b', 'c', 'd')
Using hdf5 in Python, I can see that a is represented as
array([3707764736, 2, 1, 1, 1, 1], dtype=uint32)
and b is
array([3707764736, 2, 1, 1, 1, 2], dtype=uint32).
A little more digging shows that '#refs#/e' yields a's Name, and '#refs#/f' yields its Value. But where does the mapping occur?

Related

How to create a bool variable to indicate if another integer variable is between two specific values

In ortools cp-sat, how could we link an boolean decision variable to whether an integer variable value is between two given values.
from ortools.sat.python import cp_model
def get(x):
return solver.Value(x)
model = cp_model.CpModel()
x_is_between_5_and_10 = model.NewBoolVar('x_is_between_5_and_10')
x = model.NewIntVar(0, 100, 'x')
model.Add(x == 7)
model.Add(x_is_between_5_and_10 == 1).OnlyEnforceIf(5 <= x).OnlyEnforceIf(x <= 10)
solver = cp_model.CpSolver()
status = solver.Solve(model=model)
print('x', get(x))
print('x_is_between_5_and_10', get(x_is_between_5_and_10))
Use:
model.AddLinearConstraint(x, 5, 10).OnlyEnforceIf(x_is_between_5_and_10).
model.AddLinearExpressionInDomain(x, cp_model.Domain.FromIntervals([[0, 4], [11, 100]])).OnlyEnforceIf(x_is_between_5_and_10.Not())
Note you can also write
model.AddLinearExpressionInDomain(x, cp_model.Domain.FromIntervals([[5, 10]])).OnlyEnforceIf(x_is_between_5_and_10)
for the first equation. But it that case, AddLinearConstraint() is smaller.
See the doc.

How to pick an element from matrix (list of list in python) based on decision variables (one for row, and one for column) | OR-Tools, Python

I am new to constraint programming and OR-Tools. A brief about the problem. There are 8 positions, for each position I need to decide which move of type A (move_A) and which move of type B (move_B) should be selected such that the value achieved from the combination of the 2 moves (at each position) is maximized. (This is only a part of the bigger problem though). And I want to use AddElement approach to do the sub setting.
Please see the below attempt
from ortools.sat.python import cp_model
model = cp_model.CpModel()
# value achieved from combination of different moves of type A
# (moves_A (rows)) and different moves of type B (moves_B (columns))
# for e.g. 2nd move of type A and 3rd move of type B will give value = 2
value = [
[ -1, 5, 3, 2, 2],
[ 2, 4, 2, -1, 1],
[ 4, 4, 0, -1, 2],
[ 5, 1, -1, 2, 2],
[ 0, 0, 0, 0, 0],
[ 2, 1, 1, 2, 0]
]
# 6 moves of type A
num_moves_A = len(value)
# 5 moves of type B
num_moves_B = len(value[0])
num_positions = 8
type_move_A_position = [model.NewIntVar(0, num_moves_A - 1, f"move_A[{i}]") for i in range(num_positions)]
type_move_B_position = [model.NewIntVar(0, num_moves_B - 1, f"move_B[{i}]") for i in range(num_positions)]
value_position = [model.NewIntVar(0, 10, f"value_position[{i}]") for i in range(num_positions)]
# I am getting an error when I run the below
objective_terms = []
for i in range(num_positions):
model.AddElement(type_move_B_position[i], value[type_move_A_position[i]], value_position[i])
objective_terms.append(value_position[i])
The error is as follows:
Traceback (most recent call last):
File "<ipython-input-65-3696379ce410>", line 3, in <module>
model.AddElement(type_move_B_position[i], value[type_move_A_position[i]], value_position[i])
TypeError: list indices must be integers or slices, not IntVar
In MiniZinc the below code would have worked
var int: obj = sum(i in 1..num_positions ) (value [type_move_A_position[i], type_move_B_position[i]])
I know in OR-Tools we will have to create some intermediary variables to store results first, so the above approach of minizinc will not work. But I am struggling to do so.
I can always create a 2 matrix of binary binary variables one for num_moves_A * num_positions and the other for num_moves_B * num_positions, add re;evant constraints and achieve the purpose
But I want to learn how to do the same thing via AddElement constraint
Any help on how to re-write the AddElement snippet is highly appreciated. Thanks.
AddElement is 1D only.
The way it is translated from minizinc to CP-SAT is to create an intermediate variable p == index1 * max(index2) + index2 and use it in an element constraint with a flattened matrix.
Following Laurent's suggestion (using AddElement constraint):
from ortools.sat.python import cp_model
model = cp_model.CpModel()
# value achieved from combination of different moves of type A
# (moves_A (rows)) and different moves of type B (moves_B (columns))
# for e.g. 2 move of type A and 3 move of type B will give value = 2
value = [
[-1, 5, 3, 2, 2],
[2, 4, 2, -1, 1],
[4, 4, 0, -1, 2],
[5, 1, -1, 2, 2],
[0, 0, 0, 0, 0],
[2, 1, 1, 2, 0],
]
min_value = min([min(i) for i in value])
max_value = max([max(i) for i in value])
# 6 moves of type A
num_moves_A = len(value)
# 5 moves of type B
num_moves_B = len(value[0])
# number of positions
num_positions = 5
# flattened matrix of values
value_flat = [value[i][j] for i in range(num_moves_A) for j in range(num_moves_B)]
# flattened indices
flatten_indices = [
index1 * len(value[0]) + index2
for index1 in range(len(value))
for index2 in range(len(value[0]))
]
type_move_A_position = [
model.NewIntVar(0, num_moves_A - 1, f"move_A[{i}]") for i in range(num_positions)
]
model.AddAllDifferent(type_move_A_position)
type_move_B_position = [
model.NewIntVar(0, num_moves_B - 1, f"move_B[{i}]") for i in range(num_positions)
]
model.AddAllDifferent(type_move_B_position)
# below intermediate decision variable is created which
# will store index corresponding to the selected move of type A and
# move of type B for each position
# this will act as index in the AddElement constraint
flatten_index_num = [
model.NewIntVar(0, len(flatten_indices), f"flatten_index_num[{i}]")
for i in range(num_positions)
]
# another intermediate decision variable is created which
# will store value corresponding to the selected move of type A and
# move of type B for each position
# this will act as the target in the AddElement constraint
value_position_index_num = [
model.NewIntVar(min_value, max_value, f"value_position_index_num[{i}]")
for i in range(num_positions)
]
objective_terms = []
for i in range(num_positions):
model.Add(
flatten_index_num[i]
== (type_move_A_position[i] * len(value[0])) + type_move_B_position[i]
)
model.AddElement(flatten_index_num[i], value_flat, value_position_index_num[i])
objective_terms.append(value_position_index_num[i])
model.Maximize(sum(objective_terms))
# Solve
solver = cp_model.CpSolver()
status = solver.Solve(model)
solver.ObjectiveValue()
for i in range(num_positions):
print(
str(i)
+ "--"
+ str(solver.Value(type_move_A_position[i]))
+ "--"
+ str(solver.Value(type_move_B_position[i]))
+ "--"
+ str(solver.Value(value_position_index_num[i]))
)
The below version uses AddAllowedAssignments constraint to achieve the same purpose (per Laurent's alternate approach) :
from ortools.sat.python import cp_model
model = cp_model.CpModel()
# value achieved from combination of different moves of type A
# (moves_A (rows)) and different moves of type B (moves_B (columns))
# for e.g. 2 move of type A and 3 move of type B will give value = 2
value = [
[-1, 5, 3, 2, 2],
[2, 4, 2, -1, 1],
[4, 4, 0, -1, 2],
[5, 1, -1, 2, 2],
[0, 0, 0, 0, 0],
[2, 1, 1, 2, 0],
]
min_value = min([min(i) for i in value])
max_value = max([max(i) for i in value])
# 6 moves of type A
num_moves_A = len(value)
# 5 moves of type B
num_moves_B = len(value[0])
# number of positions
num_positions = 5
type_move_A_position = [
model.NewIntVar(0, num_moves_A - 1, f"move_A[{i}]") for i in range(num_positions)
]
model.AddAllDifferent(type_move_A_position)
type_move_B_position = [
model.NewIntVar(0, num_moves_B - 1, f"move_B[{i}]") for i in range(num_positions)
]
model.AddAllDifferent(type_move_B_position)
value_position = [
model.NewIntVar(min_value, max_value, f"value_position[{i}]")
for i in range(num_positions)
]
tuples_list = []
for i in range(num_moves_A):
for j in range(num_moves_B):
tuples_list.append((i, j, value[i][j]))
for i in range(num_positions):
model.AddAllowedAssignments(
[type_move_A_position[i], type_move_B_position[i], value_position[i]],
tuples_list,
)
model.Maximize(sum(value_position))
# Solve
solver = cp_model.CpSolver()
status = solver.Solve(model)
solver.ObjectiveValue()
for i in range(num_positions):
print(
str(i)
+ "--"
+ str(solver.Value(type_move_A_position[i]))
+ "--"
+ str(solver.Value(type_move_B_position[i]))
+ "--"
+ str(solver.Value(value_position[i]))
)

Find a text and replace it with a value in Matlab

I have some data which look like this:
I would like to pre-process the data in a way that I replace all Mostly false with 1, Mostly true with 2 and Definitely true w/ 3. Is there a find and replace command or what is the best way of doing this?
You can use a map object to do the mapping
m = containers.Map( {'Mostly false', 'Mostly true', 'Definitely true'}, ...
{ 1, 2, 3} );
Then for some example data
data = {'Mostly false', 'Mostly false', 'Mostly true', 'Mostly false', 'Definitely true'};
You can perform the conversion with
data = m.values( data );
% >> data = {1, 1, 2, 1, 3}
This assumes there will always be a match in your map.
Alternatively, you could do the operation manually (for the same example data), this will leave non-matches unaltered, and you could use strcmpi for case-insensitivity:
c = {'Mostly false', 'Mostly true', 'Definitely true'
1, 2, 3};
for ii = 1:size(c,2)
% Make the replacement for each column in 'c'
data( strcmp( data, c{1,ii} ) ) = c(2,ii);
end

Proper string conversion with implicit data type in MATLAB

I have arbitrary strings that shall be converted to suited data types (i.e. scalar double, double array or string), depending on their content.
str2num() does its job when interpreting the status return value, but the function itself evaluates the content of the string which:
causes str2num('3-7') to be -4 (double), but I want to stick to '3-7' (char array)
is a severe security issue, since it can potentially execute any code
One workaround is to use str2double(), which does not end up with double arrays, but just scalars or strings. Unfortunately, isstrprop() is not really appropriate for this.
Example inputs (and outputs):
'123.4' -> 123.4 (double scalar) [covered by str2double() and str2num()]
abc' -> 'abc' (char array) [inherently covered by str2double() and str2num()]
'123,456' -> [123, 456] (double array) [covered by str2num() only]
'3-7' -> '3-7' (char array) [don't know how to cover]
use str2double and strsplit:
C = {'123.4','abc','123,456','3-7'};
for ii = 1:numel(C)
CC = strsplit(C{ii},',');
res = [str2double(CC)];
if isnan(res)
res = C{ii};
end
disp(res)
disp(class(res))
disp('****************')
end
shows:
123.4000
double
****************
abc
char
****************
123 456
double
****************
3-7
char
****************
Solution (thanks to #user2999345):
function res = str2impl(str, delimiter)
narginchk(1,2);
if isempty(str)
res = [];
return
end
if nargin < 2
delimiter = ',';
end
splits = strsplit(str, delimiter);
res = str2double(splits);
if any(isnan(res)) & ~strcmpi(str, 'NaN') % NaN not specifically requested
res = str;
end
ends up in
C = {'123.4','abc','123,456','3-7','NaN','',[]};
for ii = 1:numel(C)
r{ii,1} = str2impl(C{ii});
end
disp(r)
[ 123.4000]
'abc'
[1×2 double]
'3-7'
[ NaN]
[]
[]

Matlab subsref and end

I have a custom matrix class, that I want to be able to index as:
x = myobj(1,2).d(3,4) % myobj(1,2,3,4)
x = myobj(2, 3).d(3, end) % myobj(1,3,1,end)
I want these to work for assignment too.
I've started with:
class MyClass < double
methods
function obj = MyClass(x)
obj = obj#double(x);
end
function obj = subsref(obj, s)
varargout{:} = subsref#double(obj, subsintercept(obj, s));
end
function obj = subsasgn(obj, s, b)
obj = subsasgn#double(obj, subsintercept(obj, s), b);
end
end
end
And then I can mess with the indexing in subsintercept. However, I've hit a problem. With a minimal implementation:
function s = subsintercept(obj, s)
disp('subsintercept');
for i = 1:length(s)
disp(s(i));
end
end
I get this expected behaviour
>> myobj = MyClass(zeros(1,2,3,4))
>> myobj(1,2).d(3,4)
subsintercept
type: '()'
subs: {[1] [2]}
type: '.'
subs: 'd'
type: '()'
subs: {[3] [4]}
<error due to not having finished subsintercept yet>
But this unexpected
>> myobj(1,2).d(3,end)
subsintercept
type: '()'
subs: {[1] [2]}
type: '.'
subs: 'd'
<error due to not having finished subsintercept yet>
Why does adding the end cause me not to receive the 3?
Is this behaviour documented?
Some testing reveals that this:
result = myobj(1,2).d(3,end)
Is translated to:
end_ = str2func('end');
d_temp = subsref(myobj, substruct('()', {1 2}, '.', 'd'));
ei = end_(d_temp, 2, 2);
result = subsref(myobj, substruct('()', {1 2}, '.', 'd', '()', {3, ei}));
i.e., that subsref gets called twice!*
*And surprisingly, not as subsref(d_temp, substruct('()', {3, ei}))the second time