AttributeError: 'str' object has no attribute 'dot' - python

I am using the qndiag library to try to find a diagonalisation for 2 given matrices.
The github is here : qndiag libray
I am using this Python script to compute these 2 diagonalisation as closed as possible :
import os, sys
import numpy as np
from qndiag import qndiag
# dimension
m=7
# number of matrices
n=2
# Load spectro and WL+GCph+XC
FISH_GCsp = np.loadtxt('Fisher_GCsp_flat.txt')
FISH_XC = np.loadtxt('Fisher_XC_GCph_WL_flat.txt')
# Marginalizing over uncommon parameters between the two matrices
COV_GCsp_first = np.linalg.inv(FISH_GCsp)
COV_XC_first = np.linalg.inv(FISH_XC)
COV_GCsp = COV_GCsp_first[0:m,0:m]
COV_XC = COV_XC_first[0:m,0:m]
# Invert to get Fisher matrix
FISH_sp = np.linalg.inv(COV_GCsp);
FISH_xc = np.linalg.inv(COV_XC);
# Drawing a random set of commuting matrices
C=np.zeros((n,m,m));
C[0,:,:] = FISH_sp
C[1,:,:] = FISH_xc
[D, B] = qndiag(C, 'max_iter', 1000, 'tol', 1e-3);
# Print expected diagonal matrices
B*C[0,:,:]*B.T
B*C[1,:,:]*B.T
Given my 2 matrices 7x7 FISH_sp and FISH_xc, I get an error of kind :
approximate_joint_diagonalization_qndiag/qndiag/qndiag/qndiag.py", line 90, in qndiag
D = transform_set(B, C)
and following
approximate_joint_diagonalization_qndiag/qndiag/qndiag/qndiag.py", line 151, in transform_set
op[i] = M.dot(d.dot(M.T))
AttributeError: 'str' object has no attribute 'dot'
Here the concerned function transform_set :
def transform_set(M, D, diag_only=False):
n, p, _ = D.shape
if not diag_only:
op = np.zeros((n, p, p))
for i, d in enumerate(D):
op[i] = M.dot(d.dot(M.T))
and the main function that is called in my initialization :
def qndiag(C, B0=None, weights=None, max_iter=1000, tol=1e-6,
lambda_min=1e-4, max_ls_tries=10, diag_only=False,
return_B_list=False, verbose=False):
"""Joint diagonalization of matrices using the quasi-Newton method
Parameters
----------
C : array-like, shape (n_samples, n_features, n_features)
Set of matrices to be jointly diagonalized. C[0] is the first matrix,
etc...
B0 : None | array-like, shape (n_features, n_features)
Initial point for the algorithm. If None, a whitener is used.
weights : None | array-like, shape (n_samples,)
Weights for each matrix in the loss:
L = sum(weights * KL(C, C')) / sum(weights).
No weighting (weights = 1) by default.
max_iter : int, optional
Maximum number of iterations to perform.
tol : float, optional
A positive scalar giving the tolerance at which the
algorithm is considered to have converged. The algorithm stops when
|gradient| < tol.
lambda_min : float, optional
A positive regularization scalar. Each eigenvalue of the Hessian
approximation below lambda_min is set to lambda_min.
max_ls_tries : int, optional
Maximum number of line-search tries to perform.
diag_only : bool, optional
If true, the line search is done by computing only the diagonals of the
dataset. The dataset is then computed after the line search.
Taking diag_only = True might be faster than diag_only=False
when the matrices are large (n_features > 200)
return_B_list : bool, optional
Chooses whether or not to return the list of iterates.
verbose : bool, optional
Prints informations about the state of the algorithm if True.
Returns
-------
D : array-like, shape (n_samples, n_features, n_features)
Set of matrices jointly diagonalized
B : array, shape (n_features, n_features)
Estimated joint diagonalizer matrix.
infos : dict
Dictionnary of monitoring informations, containing the times,
gradient norms and objective values.
References
----------
P. Ablin, J.F. Cardoso and A. Gramfort. Beyond Pham's algorithm
for joint diagonalization. Proc. ESANN 2019.
https://www.elen.ucl.ac.be/Proceedings/esann/esannpdf/es2019-119.pdf
https://hal.archives-ouvertes.fr/hal-01936887v1
https://arxiv.org/abs/1811.11433
"""
t0 = time()
n_samples, n_features, _ = C.shape
if B0 is None:
C_mean = np.mean(C, axis=0)
d, p = np.linalg.eigh(C_mean)
B = p.T / np.sqrt(d[:, None])
else:
B = B0
if weights is not None: # normalize
weights_ = weights / np.mean(weights)
else:
weights_ = None
D = transform_set(B, C)
Why this error on dot operator ? it seems to be matricial product (like np.dot) but the way it is used lets think that's not the case.

The issue lies in [D, B] = qndiag(C, 'max_iter', 1000, 'tol', 1e-3), B0 (which is the second param) gets assigned as a string not as an array! Then eventually B would be a string and hence the error message str object has no attribute 'dot' !, if you are only passing C matrix as parameter, just do [D, B] = qndiag(C).

Related

Understanding fancy einsum equation

I was reading about attention and came across this equation:
import einops
from fancy_einsum import einsum
import torch
x = torch.rand((200, 10, 768))
y = torch.rand((20, 768, 64))
res = einsum("batch query_pos d_model, n_heads d_model d_head -> batch query_pos n_heads d_head", x, y)
And I am not able to understand the underlying operations that give the result res
I thought it might be matmul and tried this:
import torch
x_ = x.unsqueeze(dim = 2).unsqueeze(dim = 2)
y_ = torch.broadcast_to(y, (1, 1, 20, 768, 64))
res2 = x_ # y_
res2 = res2.squeeze(dim = -2)
(res == res2).all() # Prints False
But that does not seem to be right.
Any help regarding this is greatly appreciated
So whenever using einsum you best think about the meaning of the dimensions. Basically we perform a multiplication between the two inputs in this case. The signature passed to einsum shows what dimensions will be preserved and which ones will be "summed away". I simplified the signature with single letters here:
res = einsum("b q m, n m h -> b q n h", x, y)
We can read from this that both x and y have three dimensions. Furthermore both have a dimension called m, and this doesn't appear in the output. So we can conclude that it gets "summed away". So for each entry of the output we have following formula. For simplicity I reused the dimension names as indices, so for every b,q,n,h we get
___
\
res[b,q,n,h] = / x[b,q,m] * y[n,m,h]
/__
m
To do this with any other function than einsum is usually more cumbersome. So first we need to reorder and unsqueeze the dimensions in a way that they are compatible to be multiplied, so we can do the following (the shapes annotated above):
#(b,q,m,n,h) (b, q, m, 1, 1) (m, n, h)
product = x[:, :, :, None, None] * y.permute([1,0,2])
Due to the broadcasting rules, the second (y-) term will implicitly get the required leading dummy dimensions.
Then we can "sum away" the dimension m:
res = product.sum(dim=2) # (b,q,n,h)
So you can interpret that as a matrix multiplication if you want, or also just a scalar product, but of course with many "batch"-dimensions.

Principal Component Analysis (PCA) in Python numpy using the Snapshot method

I am trying to implement PCA analysis using numpy to mimic the results from sklearn's decomposition.PCA classifier.
I am using as input vectors of N flattened images of fixed size M = 128x192 (image dimensions) joined horizontally into a single matrix D of dimensions MxN
I am aiming to use the Snapshot method, as other implementations (see here and here) crash my build while computing np.cov, since the size of the covariant matrix would be C = D(D^T) = MxM.
The snapshot method first computes C_acute = (D^T)D, then computes the (acute) eigenvectors and values of this NxN matrix. This gives eigenvectors that are (D^T)v, and eigenvalues that are the same.
To retrieve the eigenvectors v from the (acute) eigenvectors, we simply do v = (1/eigenvalue) * (D(v_acute)).
Here is the reference implementation I am using adapted from this SO post (which is known to work):
class TemplatePCA:
def __init__(self, n_components=None):
self.n_components = n_components
def fit_transform(self, X):
X -= np.mean(X, axis = 0)
R = np.cov(X, rowvar=False)
# calculate eigenvectors & eigenvalues of the covariance matrix
evals, evecs = np.linalg.eig(R)
# sort eigenvalue in decreasing order
idx = np.argsort(evals)[::-1]
evecs = evecs[:,idx]
# sort eigenvectors according to same index
evals = evals[idx]
# select the first n eigenvectors (n is desired dimension
# of rescaled data array, or dims_rescaled_data)
evecs = evecs[:, :self.n_components]
# carry out the transformation on the data using eigenvectors
# and return the re-scaled data
return -1 * np.dot(X, evecs) #
Here is the implementation I have so far.
class MyPCA:
def __init__(self, n_components=None):
self.n_components = n_components
def fit_transform(self, X):
X -= np.mean(X, axis = 0)
D = X.T
M, N = D.shape
D_T = X # D.T == (X.T).T == X
C_acute = np.dot(D_T, D)
eigen_values, eigen_vectors_acute = np.linalg.eig(C_acute)
eigen_vectors = []
for i in range(eigen_vectors_acute.shape[0]): # for each eigenvector
v = np.dot(D, eigen_vectors_acute[i]) / eigen_values[i]
eigen_vectors.append(v)
eigen_vectors = np.array(eigen_vectors)
# sort eigenvalues and eigenvectors in decreasing order
idx = np.argsort(eigen_values)[::-1]
eigen_vectors = eigen_vectors[:,idx]
eigen_values = eigen_values[idx]
# select the first n_components eigenvectors
eigen_vectors = eigen_vectors[:, :self.n_components]
# carry out the transformation on the data using eigenvectors
# return the re-scaled data (projection)
return np.dot(C_acute, eigen_vectors)
The reference text I am using notes that:
The eigenvector is now (D^T)v, so to do face detection we first multiply our test image vector by (D^T) before projecting onto the eigenimages.
I am not sure whether it is possible to retrieve the exact same principal components (i.e. eigenvectors) using this method, and it would seem impossible to even get the same eigenvectors back, since the size of the eigen_vectors_acute is only (4, 6) (meaning there are only 4 vectors), compared to the other method where it is (6, 6) (there are 6).
Running both on an input:
x = np.array([
[0.387,123, 789,256, 4878, 5.42],
[0.723,9.78,1.90,1234, 12104,5.25],
[1,123, 67.98,7.91,12756,5.52],
[1.524,1.34,23.456,1.23,6787,3.94],
])
# These two are the same
print(sklearn.decomposition.PCA(n_components=3).fit_transform(x))
print(TemplatePCA(n_components=3).fit_transform(x))
# This one is different
print(MyPCA(n_components=3).fit_transform(x))
Output:
[[ 4282.20163145 147.84415964 -267.73483211]
[-3025.62452358 683.58580386 67.76941319]
[-3599.15380006 -569.33984612 -148.62757658]
[ 2342.57669218 -262.09011737 348.5929955 ]]
[[-4282.20163145 -147.84415964 267.73483211]
[ 3025.62452358 -683.58580386 -67.76941319]
[ 3599.15380006 569.33984612 148.62757658]
[-2342.57669218 262.09011737 -348.5929955 ]]
[[ 3.35535639e+15, -5.70493660e+17, -8.57482740e+17],
[-2.45510474e+15, 4.17428591e+17, 6.27417685e+17],
[-2.82475918e+15, 4.80278997e+17, 7.21885236e+17],
[ 1.92450753e+15, -3.27213928e+17, -4.91820181e+17]]

Error with the structure of array passed as argument for joint diagonalisation

I am trying to use ffdiag (pybss) from the following function :
def ffdiag(X, max_lag = 10, eps = 1.0e-10, max_iter = 100):
'''
Blind source separation using FFDIAG. This version does not require that
the estimated mixing matrix be orthogonal.
INPUT:
------
X : array, required
N_sig x t matrix of signal mixtures
max_lag : int, optional
maximum lag (in samples) for covariance matrix calculation
eps : double, optional
convergence criterion for matrix updates
max_iter : int, optional
maximum number of iterations/updates
'''
R_tau = linalg.lagged_covariance(X,max_lag)
dim = len(R_tau[0])
n_lags = len(R_tau.keys())
W = zeros((dim,dim))
V = eye(dim)
C = R_tau
niter = 0
theta = 0.9
iter_eps = 1.0
with lagged_covariance defined by :
def lagged_covariance(X, max_lag):
'''
Generates a dictionary of lagged covariance matrices of matrix X, for
lags 0,1,2,...,max_lag.
INPUT:
------
X : array, required
N x t data matrix
max_lag : integer, required
covariance matrices will be computed for lags 0,1,...,max_lag
OUTPUT:
------
R_tau : dictionary, keyed on the lag, with values equal to the lagged
covariance of X with the lagged version of itself.
'''
R_tau = {}
t = X.shape[1]
dim = X.shape[0]
R_tau[0] = cov(X,X)[0:dim,dim::]
for tau in range(1,max_lag+1):
for i in range(tau,t):
# create X(t) and X(t-tau)
X_t = X[:,0:t-tau]
I get the following error :
/Users/henry/pybss/linalg.py", line 92, in lagged_covariance
R_tau[0] = cov(X,X)[0:dim,dim::]
File "<__array_function__ internals>", line 6, in cov
File "/opt/intel/intelpython3/lib/python3.7/site-packages/numpy/lib/function_base.py", line 2371, in cov
raise ValueError("m has more than 2 dimensions")
ValueError: m has more than 2 dimensions
In my script, I am calling ffdiag like this :
# dimension
m=7
# number of matrices
n=2
# Load spectro and WL+GCph+XC
FISH_GCsp = np.loadtxt('Fisher_GCsp_flat.txt')
FISH_XC = np.loadtxt('Fisher_XC_GCph_WL_flat.txt')
# Marginalizing over uncommon parameters between the two matrices
COV_GCsp_first = np.linalg.inv(FISH_GCsp)
COV_XC_first = np.linalg.inv(FISH_XC)
COV_GCsp = COV_GCsp_first[0:m,0:m]
COV_XC = COV_XC_first[0:m,0:m]
# Invert to get Fisher matrix
FISH_sp = np.linalg.inv(COV_GCsp)
FISH_xc = np.linalg.inv(COV_XC)
# Drawing a random set of commuting matrices
C=np.zeros((n,m,m));
B=np.zeros((n,m,m));
C[0,:,:] = np.array(FISH_sp)
C[1,:,:] = np.array(FISH_xc)
[invV, B, ut] = ffdiag(C, 10, 1.0e-10, 100)
but I don't know if the array C is well defined : in any cases, I have got to pass 2 matrices of size 7x7 but in which order :
# dimension
m=7
# number of matrices
n=2
C=np.zeros((n,m,m));
B=np.zeros((n,m,m));
or
C=np.zeros((m,m,n));
B=np.zeros((m,m,n));
or something else since the both above don't seem to work.
As you can see in the definition of ffdiag, it is noticed :
INPUT:
------
X : array, required
N_sig x t matrix of signal mixtures
But I can't guess which is the structure of X array.

Why can't my covariance be calculated by scipy.optimize.curve_fit?

I am trying to fit a curve to this set of data using the optimize.curve_fit method in Spyder. I keep getting the optimize warning: cannot calculate covariance error. Could someone please explain why I keep getting this error?
time_in_days = np.array([0, 0.0831, 0.1465, 0.2587, 0.4828, 0.7448, 0.9817, 1.2563, 1.4926, 1.7299, 1.9915, 3.0011, 4.0109, 5.009, 5.9943, 7.0028])
viral_load = np.array([106000, 93240, 167000, 154000, 119000, 117000, 110000, 111000, 74388, 83291, 66435, 21125, 20450, 15798, 4785.2])
#defining function
def VL_func(time, A, B, alpha, beta):
"""
Parameters
----------
time : Time in days
A : constant
B : constant
alpha : constant
beta : constant
Returns VL
------
"""
VL = (A * np.exp(-alpha * time_in_days)) + (B * np.exp(-beta * time_in_days))
return np.round(VL)
popt, pcov = curve_fit(VL_func, time_in_days, viral_load)
print(popt)
print("\n")
print(pcov)
error message:
OptimizeWarning: Covariance of the parameters could not be estimated
category=OptimizeWarning
As you can see here, the shape of your data is important.
I've reproduced your problem here, and going a little deeper I found this. Your variable time_in_days and viral_load have different lengths.
ValueError: operands could not be broadcast together with shapes (16,) (15,)

How to run a .py module?

I've got zero experience with Python. I have looked around some tutorial materials, but it seems difficult to understand a advanced code. So I came here for a more specific answer.
For me the mission is to redo the code in my computer.
Here is the scenario:
I'm a graduate student studying tensor factorization in relation learning. A paper[1] providing a code to run this algorithm, as follows:
import logging, time
from numpy import dot, zeros, kron, array, eye, argmax
from numpy.linalg import qr, pinv, norm, inv
from scipy.linalg import eigh
from numpy.random import rand
__version__ = "0.1"
__all__ = ['rescal', 'rescal_with_random_restarts']
__DEF_MAXITER = 500
__DEF_INIT = 'nvecs'
__DEF_PROJ = True
__DEF_CONV = 1e-5
__DEF_LMBDA = 0
_log = logging.getLogger('RESCAL')
def rescal_with_random_restarts(X, rank, restarts=10, **kwargs):
"""
Restarts RESCAL multiple time from random starting point and
returns factorization with best fit.
"""
models = []
fits = []
for i in range(restarts):
res = rescal(X, rank, init='random', **kwargs)
models.append(res)
fits.append(res[2])
return models[argmax(fits)]
def rescal(X, rank, **kwargs):
"""
RESCAL
Factors a three-way tensor X such that each frontal slice
X_k = A * R_k * A.T. The frontal slices of a tensor are
N x N matrices that correspond to the adjecency matrices
of the relational graph for a particular relation.
For a full description of the algorithm see:
Maximilian Nickel, Volker Tresp, Hans-Peter-Kriegel,
"A Three-Way Model for Collective Learning on Multi-Relational Data",
ICML 2011, Bellevue, WA, USA
Parameters
----------
X : list
List of frontal slices X_k of the tensor X. The shape of each X_k is ('N', 'N')
rank : int
Rank of the factorization
lmbda : float, optional
Regularization parameter for A and R_k factor matrices. 0 by default
init : string, optional
Initialization method of the factor matrices. 'nvecs' (default)
initializes A based on the eigenvectors of X. 'random' initializes
the factor matrices randomly.
proj : boolean, optional
Whether or not to use the QR decomposition when computing R_k.
True by default
maxIter : int, optional
Maximium number of iterations of the ALS algorithm. 500 by default.
conv : float, optional
Stop when residual of factorization is less than conv. 1e-5 by default
Returns
-------
A : ndarray
array of shape ('N', 'rank') corresponding to the factor matrix A
R : list
list of 'M' arrays of shape ('rank', 'rank') corresponding to the factor matrices R_k
f : float
function value of the factorization
iter : int
number of iterations until convergence
exectimes : ndarray
execution times to compute the updates in each iteration
"""
# init options
ainit = kwargs.pop('init', __DEF_INIT)
proj = kwargs.pop('proj', __DEF_PROJ)
maxIter = kwargs.pop('maxIter', __DEF_MAXITER)
conv = kwargs.pop('conv', __DEF_CONV)
lmbda = kwargs.pop('lmbda', __DEF_LMBDA)
if not len(kwargs) == 0:
raise ValueError( 'Unknown keywords (%s)' % (kwargs.keys()) )
sz = X[0].shape
dtype = X[0].dtype
n = sz[0]
k = len(X)
_log.debug('[Config] rank: %d | maxIter: %d | conv: %7.1e | lmbda: %7.1e' % (rank,
maxIter, conv, lmbda))
_log.debug('[Config] dtype: %s' % dtype)
# precompute norms of X
normX = [norm(M)**2 for M in X]
Xflat = [M.flatten() for M in X]
sumNormX = sum(normX)
# initialize A
if ainit == 'random':
A = array(rand(n, rank), dtype=dtype)
elif ainit == 'nvecs':
S = zeros((n, n), dtype=dtype)
T = zeros((n, n), dtype=dtype)
for i in range(k):
T = X[i]
S = S + T + T.T
evals, A = eigh(S,eigvals=(n-rank,n-1))
else :
raise 'Unknown init option ("%s")' % ainit
# initialize R
if proj:
Q, A2 = qr(A)
X2 = __projectSlices(X, Q)
R = __updateR(X2, A2, lmbda)
else :
R = __updateR(X, A, lmbda)
# compute factorization
fit = fitchange = fitold = f = 0
exectimes = []
ARAt = zeros((n,n), dtype=dtype)
for iter in xrange(maxIter):
tic = time.clock()
fitold = fit
A = __updateA(X, A, R, lmbda)
if proj:
Q, A2 = qr(A)
X2 = __projectSlices(X, Q)
R = __updateR(X2, A2, lmbda)
else :
R = __updateR(X, A, lmbda)
# compute fit value
f = lmbda*(norm(A)**2)
for i in range(k):
ARAt = dot(A, dot(R[i], A.T))
f += normX[i] + norm(ARAt)**2 - 2*dot(Xflat[i], ARAt.flatten()) + lmbda*(R[i].flatten()**2).sum()
f *= 0.5
fit = 1 - f / sumNormX
fitchange = abs(fitold - fit)
toc = time.clock()
exectimes.append( toc - tic )
_log.debug('[%3d] fit: %.5f | delta: %7.1e | secs: %.5f' % (iter,
fit, fitchange, exectimes[-1]))
if iter > 1 and fitchange < conv:
break
return A, R, f, iter+1, array(exectimes)
def __updateA(X, A, R, lmbda):
n, rank = A.shape
F = zeros((n, rank), dtype=X[0].dtype)
E = zeros((rank, rank), dtype=X[0].dtype)
AtA = dot(A.T,A)
for i in range(len(X)):
F += dot(X[i], dot(A, R[i].T)) + dot(X[i].T, dot(A, R[i]))
E += dot(R[i], dot(AtA, R[i].T)) + dot(R[i].T, dot(AtA, R[i]))
A = dot(F, inv(lmbda * eye(rank) + E))
return A
def __updateR(X, A, lmbda):
r = A.shape[1]
R = []
At = A.T
if lmbda == 0:
ainv = dot(pinv(dot(At, A)), At)
for i in range(len(X)):
R.append( dot(ainv, dot(X[i], ainv.T)) )
else :
AtA = dot(At, A)
tmp = inv(kron(AtA, AtA) + lmbda * eye(r**2))
for i in range(len(X)):
AtXA = dot(At, dot(X[i], A))
R.append( dot(AtXA.flatten(), tmp).reshape(r, r) )
return R
def __projectSlices(X, Q):
q = Q.shape[1]
X2 = []
for i in range(len(X)):
X2.append( dot(Q.T, dot(X[i], Q)) )
return X2
It's boring to paste such a long code but there is no other way to figure out my problems. I'm sorry about this.
I import this module and pass them arguments according to the author's website:
import pickle, sys
from rescal import rescal
rank = sys.argv[1]
X = pickle.load('us-presidents.pickle')
A, R, f, iter, exectimes = rescal(X, rank, lmbda=1.0)
The dataset us-presidents.rdf can be found here.
My questions are:
According to the code note, the tensor X is a list. I don't quite understand this, how do I relate a list to a tensor in Python? Can I understand tensor = list in Python?
Should I convert RDF format to a triple(subject, predicate, object) format first? I'm not sure of the data structure of X. How do I assignment values to X by hand?
Then, how to run it?
I paste the author's code without his authorization, is it an act of infringement? if so, I am so sorry and I will delete it soon.
The problems may be a little bored, but these are important to me. Any help would be greatly appreciated.
[1] Maximilian Nickel, Volker Tresp, Hans-Peter Kriegel,
A Three-Way Model for Collective Learning on Multi-Relational Data,
in Proceedings of the 28th International Conference on Machine Learning, 2011 , Bellevue, WA, USA
To answer Q2: you need to transform the RDF and save it before you can load it from the file 'us-presidents.pickle'. The author of that code probably did that once because the Python native pickle format loads faster. As the pickle format includes the datatype of the data, it is possible that X is some numpy class instance and you would need either an example pickle file as used by this code, or some code doing the pickle.dump to figure out how to convert from RDF to this particular pickle file as rescal expects it.
So this might answer Q1: the tensor consists of a list of elements. From the code you can see that the X parameter to rescal has a length (k = len(X) ) and can be indexed (T = X[i]). So it elements are used as a list (even if it might be some other datatype, that just behaves as such.
As an aside: If you are not familiar with Python and are just interested in the result of the computation, you might get more help contacting the author of the software.
According to the code note, the tensor X is a list. I don't quite understand this, how do I relate a list to a tensor in Python? Can I
understand tensor = list in Python?
Not necessarily but the author of the code has decided to represent the tensor data as a list data structure. As the comments indicate, the list X contains:
List of frontal slices X_k of the tensor X. The shape of each X_k is ('N', 'N')
That means the tensor is repesented as a list of tuples: [(N, N), ..., (N, N)].
I'm not sure of the data structure of X. How do I assignment values to X by hand?
Now that we now the data structure of X, we can assign values to it using assignment. The following will assign the tuple (1, 3) to the first position in the list X (as the first position is at index 0, the second at position 1, et cetera):
X[0] = (1, 3)
Similarly, the following will assign the tuple (2, 4) to the second position:
X[1] = (2, 4)

Categories

Resources