← Back to the problem

Romania ROAI 2025 · Correction by IOAI Training

Theory Test (17 problems)

This page gives the full approach. Read it once you have searched.

Metric
hand-marked written answers
Evaluated on
written answers
Our score
all 17 problems solved, no key published

We solved the problem ourselves: downloaded the data, ran the experiments and measured the score below. The statement and data belong to their organisers.

The problem in brief

This is the written theory paper of the June 2025 training camp of the Romanian national AI team. It has 17 short problems that sweep the whole classical AI syllabus: data preparation (scaling, outliers, encoding, regularisation), probabilistic and tree classifiers, k-means, game search (minimax and alpha-beta), heuristic search (A*), logic and resolution, constraint satisfaction, approximate Q-learning, evaluation metrics, kernels and recommender systems. Each problem is a small hand computation followed by a "why" question. The paper is in Romanian; the answers below are our own derivations, and every number was rechecked with a short Python script (solution.py).

How you are scored

The paper is marked by hand. The published PDF gives no point scale and no answer key, so there is no threshold to compare with. What a marker looks for is visible in the wording: a correct number and a justification (several sub-questions say "Argumentați", "justify", and Problem 10 explicitly gives no credit to a proof that does not use resolution). The corrections below therefore always show the reasoning, not just the result.

Question by question

Problem 1: scaling and outliers

The table has a monthly income in euros (1 000 to 12 000) and a satisfaction score from 0 to 10.

a) A distance such as (Δincome)2+(Δscore)2\sqrt{(\Delta \text{income})^2 + (\Delta \text{score})^2} adds the two columns as if they had the same unit. A difference of 1 000 euros then counts a million times more than a difference of 1 point of satisfaction, so k-NN effectively ignores the score. Normalising puts both columns on a comparable scale, for example min-max scaling x′=(x−min⁡)/(max⁡−min⁡)x' = (x - \min)/(\max - \min) or standardisation x′=(x−μ)/σx' = (x - \mu)/\sigma.

b) Sorted incomes: 1000,2300,3100,4500,5000,120001000, 2300, 3100, 4500, 5000, 12000. With the "median of each half" rule, Q1=2300Q_1 = 2300 and Q3=5000Q_3 = 5000, so IQR=2700\text{IQR} = 2700 and the fences are

Q1−1.5 IQR=−1750,Q3+1.5 IQR=9050.Q_1 - 1.5\,\text{IQR} = -1750, \qquad Q_3 + 1.5\,\text{IQR} = 9050 .

12 000 is the only outlier. Other quartile conventions move the fences a little (NumPy's linear interpolation gives Q1=2500Q_1 = 2500, Q3=4875Q_3 = 4875 and an upper fence of 8 437.5), but the verdict does not change.

c) Robust scaling, x′=(x−median)/IQRx' = (x - \text{median})/\text{IQR}. Standard scaling uses the mean and the standard deviation, which the 12 000 inflates: the mean jumps to 4 650 and the five ordinary users get squeezed together. The median and the IQR barely notice one extreme value.

Problem 2: encoding categories

a) CategorieAliment (dairy, meat, vegetables) is nominal: there is no natural order. Use one-hot encoding (three 0/1 columns). Mapping the categories to 0, 1, 2 would invent an order and distances (meat "between" dairy and vegetables) that a model would take seriously. ConținutGrăsime (low, medium, high) is ordinal, so ordinal encoding low = 0, medium = 1, high = 2 keeps the information that high > medium > low in a single column.

b) Min-max with min⁡=3.5\min = 3.5 and max⁡=13.5\max = 13.5, so a range of 10:

IDpricescaled
15.40.19
213.51.00
33.80.03
411.00.75
53.50.00

Problem 3: L1 or L2?

The L2 penalty λ∑jwj2\lambda \sum_j w_j^2 has gradient 2λwj2\lambda w_j, which shrinks every coefficient proportionally and never quite reaches zero. The L1 penalty λ∑j∣wj∣\lambda \sum_j |w_j| pushes every nonzero coefficient with the same force λ\lambda, so small coefficients hit exactly zero.

  • a) many correlated features, shrink them without removing them: L2 (Ridge);
  • b) remove irrelevant features, automatic selection: L1 (Lasso);
  • c) only a small subset of features matters (a sparse truth): L1 (Lasso);
  • d) a penalty spread evenly over all coefficients: L2 (Ridge).

Problem 4: Naive Bayes for Josh

Josh is absent on days 1 to 4 and present on days 5 to 10.

a) Counting (maximum likelihood estimation):

Y=0Y=0 (4 days)Y=1Y=1 (6 days)
P(Y)P(Y)0.40.6
P(Xc=1∣Y)P(X_c = 1 \mid Y)0/4 = 03/6 = 1/2
P(Xm=1∣Y)P(X_m = 1 \mid Y)0/4 = 02/6 = 1/3
P(Xp=1∣Y)P(X_p = 1 \mid Y)2/4 = 1/24/6 = 2/3

(The probabilities for value 0 are the complements.)

b) For Xc=0,Xm=0,Xp=1X_c = 0, X_m = 0, X_p = 1:

P(Y=0) P(x∣Y=0)=0.4⋅1⋅1⋅12=0.200,P(Y{=}0)\,P(x \mid Y{=}0) = 0.4 \cdot 1 \cdot 1 \cdot \tfrac12 = 0.200 , P(Y=1) P(x∣Y=1)=0.6⋅12⋅23⋅23≈0.133.P(Y{=}1)\,P(x \mid Y{=}1) = 0.6 \cdot \tfrac12 \cdot \tfrac23 \cdot \tfrac23 \approx 0.133 .

Absent is more likely: after normalising, P(Y=1∣x)=0.133/0.333=0.4P(Y{=}1 \mid x) = 0.133/0.333 = 0.4.

c) With k=1k = 1 and V=2V = 2 values per sensor, every count gets +1+1 and every denominator +2+2:

Y=0Y=0Y=1Y=1
P(Xc=1∣Y)P(X_c = 1 \mid Y)1/64/8 = 1/2
P(Xm=1∣Y)P(X_m = 1 \mid Y)1/63/8
P(Xp=1∣Y)P(X_p = 1 \mid Y)3/6 = 1/25/8

The main change is that no probability is 0 any more. Under MLE, a single pressure or motion reading would force P(Y=0∣x)=0P(Y{=}0 \mid x) = 0, whatever the other sensors say, which is far too confident after only 4 absent days. For the new observation, 0.4⋅56⋅56⋅12≈0.1390.4 \cdot \frac56 \cdot \frac56 \cdot \frac12 \approx 0.139 against 0.6⋅12⋅58⋅58≈0.1170.6 \cdot \frac12 \cdot \frac58 \cdot \frac58 \approx 0.117: the decision is still absent, but less clearly (P(Y=1∣x)≈0.46P(Y{=}1 \mid x) \approx 0.46). Smoothing the prior as well, (4+1)/12(4+1)/12 and (6+1)/12(6+1)/12, gives the same decision.

Problem 5: a decision tree for the exam

The six students: 4 passed, 2 failed.

a) E(Examen)=−23log⁡223−13log⁡213=log⁡23−23≈1.58−0.67=0.92E(\text{Examen}) = -\frac23 \log_2 \frac23 - \frac13 \log_2 \frac13 = \log_2 3 - \frac23 \approx 1.58 - 0.67 = 0.92 bits.

b) For each value of Parcurs: "small" has 1 pass and 1 fail (entropy 1), "medium" also (entropy 1), "large" has 2 passes (entropy 0). Each value covers a third of the students:

E(Examen∣Parcurs)=13⋅1+13⋅1+13⋅0=23≈0.67.E(\text{Examen} \mid \text{Parcurs}) = \tfrac13 \cdot 1 + \tfrac13 \cdot 1 + \tfrac13 \cdot 0 = \tfrac23 \approx 0.67 .

c) To build the tree, compare with the other attribute. The students who studied all passed (entropy 0). Those who did not have 2 fails and 1 pass (entropy 0.92). So E(Examen∣Iˆnva˘țat)=12⋅0.92=0.46E(\text{Examen} \mid \text{Învățat}) = \frac12 \cdot 0.92 = 0.46. The information gains are 0.92−0.67=0.250.92 - 0.67 = 0.25 for Parcurs and 0.92−0.46=0.460.92 - 0.46 = 0.46 for Învățat, so the root tests "studied?":

  • studied = yes: passed (3 of 3);
  • studied = no: test Parcurs: small gives failed, medium gives failed, large gives passed.

Every leaf is pure: the tree fits the six students exactly with 4 leaves.

Problem 6: one k-means step with Manhattan distance

Distances to C1=(2,2)C_1 = (2,2) and C2=(8,9)C_2 = (8,9):

pointto C1C_1to C2C_2cluster
A(1,2)1141
B(2,1)1141
C(4,5)581
D(7,8)1122
E(8,8)1212
F(9,9)1412

b) New centroids (coordinate-wise means):

C1=(1+2+43,2+1+53)=(2.33, 2.67),C2=(8, 253)=(8, 8.33).C_1 = \left(\tfrac{1+2+4}{3}, \tfrac{2+1+5}{3}\right) = (2.33,\ 2.67), \qquad C_2 = \left(8,\ \tfrac{25}{3}\right) = (8,\ 8.33).

(With the Manhattan distance, the centre that minimises the sum of distances would be the coordinate-wise median, as in k-medians. The statement asks for the mean, so we use the mean.)

Problem 7: minimax and alpha-beta

a) Each MAX node on the third level takes the largest of its three leaves, each MIN node the smallest of those, and the root the largest MIN value:

  • MIN 1: min⁡(5,9,7)=5\min(5, 9, 7) = 5;
  • MIN 2: min⁡(10,6,9)=6\min(10, 6, 9) = 6;
  • MIN 3: min⁡(7,7,9)=7\min(7, 7, 9) = 7.

The root is worth 7. MAX plays the third branch, MIN answers with its first child (worth 7, ties broken to the left), and the game ends on the leaf 7 (the middle leaf of 3, 7, 2).

b) Yes, cuts happen. Going left to right and cutting when v≥βv \ge \beta at a MAX node or v≤αv \le \alpha at a MIN node:

The game tree with minimax values, the chosen path and the five beta cuts

  1. Under MIN 1, after the first MAX child, β=5\beta = 5. The second MAX child sees 2, then 7: since 7≥57 \ge 5, MIN will never let play reach it, and leaf 9 is pruned (beta cut).
  2. Third MAX child of MIN 1: 3, then 5, and 5≥β=55 \ge \beta = 5: leaf 7 is pruned (beta cut, on equality).
  3. At the root, α=5\alpha = 5. Under MIN 2, β\beta goes to 10, then 6. The third MAX child sees 8, and 8≥68 \ge 6: leaves 9 and 2 are pruned.
  4. Now α=6\alpha = 6. Under MIN 3, the first MAX child is worth 7, so β=7\beta = 7. The second sees 7, and 7≥77 \ge 7: leaves 6 and 5 are pruned.
  5. The third sees 9, and 9≥79 \ge 7: leaves 8 and 9 are pruned.

All five are beta cuts (at MAX nodes, because the MIN parent already has something better). There is no alpha cut: the MIN values come in increasing order (5, 6, 7), so no MIN node ever falls below the current α\alpha. Alpha-beta evaluates 19 leaves instead of 27 and still returns 7. If your course only cuts on strict inequality, cuts 2 and 4 disappear and 22 leaves are evaluated.

c) If MAX takes control of a MIN node, that node gives MAX the largest of its children, minus the cost: 9−2=79 - 2 = 7 for MIN 1, 10−2=810 - 2 = 8 for MIN 2 and 9−2=79 - 2 = 7 for MIN 3. Forcing MIN 2 to enter the subtree worth 10 gives 8 > 7, so using the ability is optimal, on the second branch. (Paying for it on the third branch would only tie with the free value 7.)

Problem 8: A* and heuristics

Edges: G-F 5, F-D 3, G-D 9, G-E 2, E-D 8, D-B 5, B-A 1, D-C 3, C-B 1, C-A 4. True distances to G (Dijkstra from G): h∗(G)=0h^*(G)=0, h∗(E)=2h^*(E)=2, h∗(F)=5h^*(F)=5, h∗(D)=8h^*(D)=8, h∗(C)=11h^*(C)=11, h∗(B)=12h^*(B)=12, h∗(A)=13h^*(A)=13.

a) Admissible means h(s)≤h∗(s)h(s) \le h^*(s) for every state. The given values all satisfy it (10≤1310 \le 13, 9≤119 \le 11, 7≤87 \le 8, 1.5≤21.5 \le 2, 4.5≤54.5 \le 5), so hh is admissible if and only if 0≤h(B)≤12\mathbf{0 \le h(B) \le 12}.

Consistent means h(u)≤c(u,v)+h(v)h(u) \le c(u,v) + h(v) for every edge, in both directions (the graph is undirected), with h(G)=0h(G) = 0. The edges that do not touch B are fine (for example h(D)=7≤3+4.5h(D) = 7 \le 3 + 4.5). The edges at B give:

  • B-A, cost 1: ∣h(B)−10∣≤1|h(B) - 10| \le 1, so 9≤h(B)≤119 \le h(B) \le 11;
  • B-C, cost 1: ∣h(B)−9∣≤1|h(B) - 9| \le 1, so 8≤h(B)≤108 \le h(B) \le 10;
  • B-D, cost 5: ∣h(B)−7∣≤5|h(B) - 7| \le 5, so 2≤h(B)≤122 \le h(B) \le 12.

So hh is consistent if and only if 9≤h(B)≤10\mathbf{9 \le h(B) \le 10}. As expected, it is a narrower window than admissibility, since consistency implies admissibility.

b) Careful: as a returned path, A → C → B → D → E → G is impossible for graph-search A*, whatever the heuristic. A is expanded first and puts B in the frontier with g=1g = 1; later, reaching B through C would cost g=5g = 5, which never replaces the better parent A. The question therefore makes sense as the order of expansion. We need, step by step:

  1. after A: f(C)=4+h(C)<f(B)=1+h(B)f(C) = 4 + h(C) < f(B) = 1 + h(B);
  2. after C (D now has g=7g = 7): 1+h(B)<7+h(D)1 + h(B) < 7 + h(D);
  3. B lowers D to g=6g = 6, then D is expanded and puts F (g=9g = 9), E (g=14g = 14) and G (g=15g = 15) in the frontier: we need 14+h(E)<9+h(F)14 + h(E) < 9 + h(F) and 14+h(E)<1514 + h(E) < 15;
  4. finally G (15) must come out before F: 15<9+h(F)15 < 9 + h(F).

h=(A:10, B:5, C:0, D:0, E:0, F:10, G:0)h = (A{:}10,\ B{:}5,\ C{:}0,\ D{:}0,\ E{:}0,\ F{:}10,\ G{:}0) satisfies all of these, and a simulation confirms the expansion order A, C, B, D, E, G. This hh is not admissible (h(F)=10>5h(F) = 10 > 5), and it has to be inadmissible: E is expanded before F although F is on the optimal route. A* then returns the path A → B → D → G of cost 15 instead of the optimal 13, which illustrates what an overestimating heuristic does.

c) Yes: g(s)=max⁡(h1(s),h2(s))g(s) = \max(h_1(s), h_2(s)). It is admissible because each of the two is at most h∗(s)h^*(s), so their maximum is too. It dominates both (g≥h1g \ge h_1 and g≥h2g \ge h_2 everywhere), and a dominating admissible heuristic never makes A* expand more nodes (for consistent heuristics, every node expanded with gg is also expanded with h1h_1 and with h2h_2). On our graph, with h1=hh_1 = h from a) and h2(s)=h_2(s) = "smallest edge leaving ss" (1 for A, 1 for B, 1 for C, 3 for D, 2 for E, 3 for F, 0 for G), gg takes h1h_1 almost everywhere but improves E to 2. By contrast, h1+h2h_1 + h_2 is not a safe choice: it can overestimate.

Problem 9: propositional resolution

a) Let PP = "PROG1 is correct" and QQ = "PROG1 produces conforming results". The premises are P→QP \to Q and PP, and the conclusion is QQ.

b) Put everything in CNF and add the negation of the conclusion:

(1) ¬P∨Q(2) P(3) ¬Q.(1)\ \neg P \lor Q \qquad (2)\ P \qquad (3)\ \neg Q .

Resolving (1) with (3) on QQ gives (4) ¬P\neg P. Resolving (4) with (2) gives the empty clause □\square. The premises plus ¬Q\neg Q are contradictory, so QQ follows: this is modus ponens, proved by refutation.

Problem 10: first-order resolution

a) With Plecat(x)Plecat(x) = "the head of xx is bowed" and Taiat(x)Taiat(x) = "the head of xx is cut by the sword", the proverb "a bowed head is not cut by the sword" becomes

∀x (Plecat(x)→¬Taiat(x)),plus the fact Taiat(Marcel).\forall x\ \big(Plecat(x) \to \neg Taiat(x)\big), \qquad \text{plus the fact } Taiat(Marcel).

The goal is ¬Plecat(Marcel)\neg Plecat(Marcel).

b) Clauses: (1) ¬Plecat(x)∨¬Taiat(x)\neg Plecat(x) \lor \neg Taiat(x), (2) Taiat(Marcel)Taiat(Marcel), (3) the negated goal Plecat(Marcel)Plecat(Marcel). Resolve (1) and (3) with the unifier {x/Marcel}\{x / Marcel\}, which gives (4) ¬Taiat(Marcel)\neg Taiat(Marcel). Resolve (4) with (2), which gives □\square. Hence Marcel's head was not bowed. (The logic is the contrapositive: no bowed head is cut, Marcel's head was cut, so it was not bowed.)

Problem 11: arc consistency (AC-3)

Domains X∈{1..10}X \in \{1..10\}, Y∈{5..10}Y \in \{5..10\}, Z∈{5..15}Z \in \{5..15\}. Constraints X>YX > Y, Y+Z=12Y + Z = 12, X+Z=15X + Z = 15.

a) An arc X→ZX \to Z is consistent if every value of XX has a supporting value of ZZ. Checking the six arcs:

  • X→YX \to Y: no (x≤5x \le 5 has no smaller yy);
  • Y→XY \to X: no (y=10y = 10 would need x=11x = 11);
  • Y→ZY \to Z: no (y=8y = 8 needs z=4z = 4);
  • Z→YZ \to Y: no (z=8z = 8 needs y=4y = 4);
  • Z→XZ \to X: no (z=15z = 15 needs x=0x = 0);
  • X→ZX \to Z: yes, since every x∈{1..10}x \in \{1..10\} has z=15−x∈{5..14}z = 15 - x \in \{5..14\}.

So exactly one arc, X→ZX \to Z, is already arc-consistent.

b) The queue starts with all arcs, in both directions: 3 binary constraints give 6 arcs. An arc (Xk,Xi)(X_k, X_i) is put back into the queue only when a value is deleted from the domain of XiX_i. A domain of size dd can lose at most dd values, so each arc enters the queue at most dd times, where dd is the largest domain size: here d=11d = 11 (the domain of ZZ). This is what gives AC-3 its O(c d3)O(c\,d^3) running time for cc constraints.

c) Running AC-3:

  1. Y→ZY \to Z with Y+Z=12Y + Z = 12: Y∈{5,6,7}Y \in \{5,6,7\};
  2. Z→YZ \to Y: Z∈{5,6,7}Z \in \{5,6,7\};
  3. X→ZX \to Z with X+Z=15X + Z = 15: X∈{8,9,10}X \in \{8,9,10\};
  4. X>YX > Y now holds for every pair (8>78 > 7), and all the other arcs are consistent.

Final domains: X∈{8,9,10}X \in \{8,9,10\}, Y∈{5,6,7}Y \in \{5,6,7\}, Z∈{5,6,7}Z \in \{5,6,7\}. Note that arc consistency does not solve the problem by itself: the real solutions are only the three triples (X,Y,Z)=(y+3, y, 12−y)(X,Y,Z) = (y+3,\ y,\ 12-y) for y∈{5,6,7}y \in \{5,6,7\}.

Problem 12: scheduling as a CSP

a) One variable per exam, MM (Math), CC (CS) and PP (Physics). Each takes a value that is a (room, slot) pair, with domain {S1,S2}×{T1,T2,T3}\{S1, S2\} \times \{T1, T2, T3\}, 6 values. Write room(⋅)room(\cdot) and time(⋅)time(\cdot) for the two parts of a value.

b) The constraints:

  • time(M)≠time(C)time(M) \neq time(C) (shared students);
  • room(P)≠room(C)room(P) \neq room(C);
  • a room hosts at most one exam per slot: M≠CM \neq C, M≠PM \neq P and C≠PC \neq P as pairs (all-different on the (room, slot) values).

c) Backtracking in the order M,C,PM, C, P, values in lexicographic order:

  1. M=(S1,T1)M = (S1, T1);
  2. CC: (S1,T1)(S1, T1) is rejected (same pair, and same slot as M); (S1,T2)(S1, T2) is accepted;
  3. PP: (S1,⋅)(S1, \cdot) is rejected (same room as C); (S2,T1)(S2, T1) is accepted (it differs from M's pair, and from C's room).

Solution: Math in S1 at T1, CS in S1 at T2, Physics in S2 at T1. No backtrack was even needed.

Problem 13: approximate Q-learning for Pacman

In the figure, Pacman sits between two ghosts (one directly to its left, one directly to its right), with a food pellet directly above. The wall below makes "down" impossible. In the current state, A(s)=2A(s) = 2 (two adjacent ghosts) and D(s)=1D(s) = 1 (one adjacent pellet).

a) The features for each action:

actionBB (ghosts hit)CC (ghosts adjacent after)Fg=A+B+CF_g = A+B+CEE (food eaten)Fp=D+2EF_p = D + 2E
left10301
right10301
up00213
stay02401

After "left", Pacman is on the ghost (distance 0, counted in BB), and the other ghost is now 2 cells away, so C=0C = 0. After "up", both ghosts are diagonal, at Manhattan distance 2, so C=0C = 0.

b) With Q=−10 Fg+100 FpQ = -10\,F_g + 100\,F_p: Q(left)=Q(right)=−30+100=70Q(\text{left}) = Q(\text{right}) = -30 + 100 = 70, Q(up)=−20+300=280Q(\text{up}) = -20 + 300 = \mathbf{280}, Q(stay)=−40+100=60Q(\text{stay}) = -40 + 100 = 60. "Up" is the best action.

c) In s′s' (the pellet's cell), no ghost and no pellet is adjacent, so A(s′)=D(s′)=0A(s') = D(s') = 0. "Down" goes back between the ghosts: Fg=0+0+2=2F_g = 0 + 0 + 2 = 2, Fp=0F_p = 0, so Q=−20Q = -20. "Stay" gives Q=0Q = 0. Then

Qnew(s,up)=250+0.5⋅max⁡(−20,0)=250.Q_{\text{new}}(s, \text{up}) = 250 + 0.5 \cdot \max(-20, 0) = 250 .

d) The error is δ=250−280=−30\delta = 250 - 280 = -30, and the features of "up" are Fg=2F_g = 2, Fp=3F_p = 3:

wg=−10+0.5⋅(−30)⋅2=−40,wp=100+0.5⋅(−30)⋅3=55.w_g = -10 + 0.5 \cdot (-30) \cdot 2 = -40, \qquad w_p = 100 + 0.5 \cdot (-30) \cdot 3 = 55 .

The prediction was too optimistic, so both weights move in the direction that lowers Q(s,up)Q(s, \text{up}). The food weight drops a lot (Pacman had overrated food), and the ghost weight becomes more negative (ghosts now look more dangerous).

Problem 14: metrics from a confusion matrix

Rows are true classes, columns predictions. Column sums: 46, 48, 56. Row sums: 50 each.

a) Precision: PA=40/46=0.870P_A = 40/46 = 0.870, PB=35/48=0.729P_B = 35/48 = 0.729, PC=40/56=0.714P_C = 40/56 = 0.714.

b) Recalls are 0.80.8, 0.70.7 and 0.80.8, so

F1A=0.833,F1B=0.714,F1C=0.755,macro-F1=0.767.F1_A = 0.833, \quad F1_B = 0.714, \quad F1_C = 0.755, \qquad \text{macro-}F1 = 0.767 .

c) Micro-averaged recall pools all the classes: 40+35+40150=0.767\frac{40 + 35 + 40}{150} = 0.767. (In single-label classification, micro recall always equals accuracy.)

d) If missing a class-C case is very costly (a rare, serious disease), maximise the recall of class C (sensitivity), possibly under a minimum-precision constraint, or use FβF_\beta with β>1\beta > 1. Ways to get there: lower the decision threshold for C (predict C as soon as P(C∣x)P(C \mid x) exceeds, say, 0.2), weight class C more in the loss (cost-sensitive learning), or rebalance the training data (oversampling C, SMOTE). Here 11 of the 50 B cases are predicted as C and 8 of the 50 C cases as B, so the B/C boundary is where to work.

Problem 15: a kernel and a non-kernel

a) There are finitely many possible 16×16 patches: N=256256N = 256^{256} of them. Index them p1,…,pNp_1, \dots, p_N, and define φ(x)∈{0,1}N\varphi(x) \in \{0,1\}^N by φi(x)=1\varphi_i(x) = 1 if patch pip_i appears somewhere in xx, and 0 otherwise. Then

φ(x)⋅φ(x′)=∑i=1Nφi(x) φi(x′)=#{i:pi appears in both}=k1(x,x′).\varphi(x) \cdot \varphi(x') = \sum_{i=1}^{N} \varphi_i(x)\,\varphi_i(x') = \#\{i : p_i \text{ appears in both}\} = k_1(x, x') .

So k1k_1 is an inner product in Rd\mathbb{R}^d with d=256256∈N∗d = 256^{256} \in \mathbb{N}^*, which makes it a kernel. The "count once" rule in the statement is exactly what makes the coordinates 0/1. An image smaller than 16×16 simply maps to the zero vector.

b) Take three images:

  • x1x_1: a 16×16 all-black square (patch aa);
  • x3x_3: a 16×16 all-white square (patch bb);
  • x2x_2: a 16×32 image, black on the left half and white on the right half, which contains both aa and bb.

x1x_1 and x3x_3 share no patch, and each image shares a patch with itself, so

G=(110111011),f=(1−11).G = \begin{pmatrix} 1 & 1 & 0 \\ 1 & 1 & 1 \\ 0 & 1 & 1 \end{pmatrix}, \qquad f = \begin{pmatrix} 1 \\ -1 \\ 1 \end{pmatrix}.

Then f⊤Gf=(1+1+1)+2(−1+0−1)=−1<0f^\top G f = (1 + 1 + 1) + 2(-1 + 0 - 1) = -1 < 0, so GG is not positive semidefinite (its eigenvalues are 1−21-\sqrt2, 11 and 1+21+\sqrt2), and k2k_2 is not a kernel. The intuition: "share at least one patch" is not transitive. x1∼x2x_1 \sim x_2 and x2∼x3x_2 \sim x_3 but x1≁x3x_1 \not\sim x_3, and no inner product of feature vectors can behave like that with these 0/1 values.

Problem 16: user-based collaborative filtering

Means over each user's own ratings: Rˉu1=5+3+13=3\bar R_{u_1} = \frac{5+3+1}{3} = 3, Rˉu2=4+3+23=3\bar R_{u_2} = \frac{4+3+2}{3} = 3, Rˉu3=1+1+5+54=3\bar R_{u_3} = \frac{1+1+5+5}{4} = 3.

a)

  • u1,u2u_1, u_2 share items 1 and 4. The deviations are (2,−2)(2, -2) and (1,−1)(1, -1), so sim=2+28 2=1\text{sim} = \frac{2 + 2}{\sqrt{8}\,\sqrt{2}} = \mathbf{1}.
  • u1,u3u_1, u_3 share items 1, 2 and 4. The deviations are (2,0,−2)(2, 0, -2) and (−2,−2,2)(-2, -2, 2), so sim=−4+0−48 12=−846=−26≈−0.82\text{sim} = \frac{-4 + 0 - 4}{\sqrt{8}\,\sqrt{12}} = \frac{-8}{4\sqrt6} = -\frac{2}{\sqrt6} \approx \mathbf{-0.82}.

u2u_2 is the most similar to u1u_1 (perfect agreement), while u3u_3 has opposite tastes.

b)

R^u1,3=3+1⋅(3−3)+(−0.82)(5−3)1+0.82=3−1.631.82≈2.10.\hat R_{u_1,3} = 3 + \frac{1\cdot(3-3) + (-0.82)(5-3)}{1 + 0.82} = 3 - \frac{1.63}{1.82} \approx 2.10 .

The negative similarity is used constructively: u3u_3 loved item 3, and since u3u_3 is an "anti-u1u_1", that pulls the prediction below u1u_1's mean. (If you compute each mean only over the co-rated items, you get slightly different numbers. Say which convention you use.)

c) A new user has no ratings, so no co-rated items, so every similarity is undefined and the formula collapses (cold start). A content-based fallback: describe each item by a feature vector cjc_j (for example genres as 0/1). Ask the new user for a few liked genres at sign-up, or use the first items they click, to build a profile vector pup_u (the average of the liked items' vectors). Then recommend the items with the highest cos⁡(pu,cj)\cos(p_u, c_j). It needs no other user, so it works from the first interaction, and you can switch progressively to collaborative filtering as ratings accumulate (a hybrid system).

Problem 17: the PQ kernel is an inner product

Index the coordinates of a feature vector by the pairs i<ji < j, so the vector has (n2)\binom{n}{2} coordinates, and set

Ψij(x)=sign⁡(xi−xj)∈{−1,+1}.\Psi_{ij}(x) = \operatorname{sign}(x_i - x_j) \in \{-1, +1\}.

(For a permutation there are no ties, so the sign is never 0.) Then

⟨Ψ(x),Ψ(y)⟩=∑i<jsign⁡(xi−xj) sign⁡(yi−yj).\langle \Psi(x), \Psi(y) \rangle = \sum_{i<j} \operatorname{sign}(x_i - x_j)\,\operatorname{sign}(y_i - y_j).

Each term is +1+1 exactly when (xi−xj)(yi−yj)>0(x_i - x_j)(y_i - y_j) > 0 (a concordant pair) and −1-1 exactly when it is <0< 0 (a discordant pair). The sum is therefore P−Q=kPQ(x,y)P - Q = k_{PQ}(x, y), an explicit inner product, so kPQk_{PQ} is a kernel. (We checked the identity on random permutations.) Dividing by (n2)\binom{n}{2} gives Kendall's τ\tau, which shows that Kendall's correlation is a normalised kernel. For rankings with ties, the same Ψ\Psi gives 0 on tied pairs, which matches the definitions of PP and QQ.

What to remember

  • Scale-sensitive models need scaling, and outliers decide which scaler. With distances (k-NN, k-means, SVM), unscaled columns silently drop out. With an outlier, use the median and the IQR, not the mean and the standard deviation.
  • Search questions are bookkeeping: write the frontier. For alpha-beta, note α\alpha and β\beta at each node and check "v≥βv \ge \beta" or "v≤αv \le \alpha". For A*, write f=g+hf = g + h at each step. Before designing a heuristic, ask whether the requested behaviour is even reachable: in Problem 8, no heuristic can make A* return a path through a worse parent.
  • Admissible means never overestimating; consistent is a triangle inequality on every edge. The max of admissible heuristics is admissible and dominates both.
  • To prove a kernel, exhibit the feature map; to disprove it, exhibit a Gram matrix with f⊤Gf<0f^\top G f < 0. Three well-chosen points usually suffice, and a non-transitive similarity is the classic counterexample.
  • Approximate Q-learning is linear regression on the TD target. δ=(r+γmax⁡a′Q(s′,a′))−Q(s,a)\delta = (r + \gamma \max_{a'} Q(s', a')) - Q(s, a), then wi+=α δ Fiw_i \mathrel{+}= \alpha\,\delta\,F_i: each weight moves in proportion to how active its feature was.
Full code (solution.py)
"""Checks every numeric answer of the ROAI 2025 camp theory paper and draws the alpha-beta figure."""
import numpy as np, heapq, math
import matplotlib; matplotlib.use('Agg'); import matplotlib.pyplot as plt

# ---------- Problem 7: minimax + alpha-beta (left to right, cut when v >= beta or v <= alpha)
L=[5,1,4,2,7,9,3,5,7,10,2,5,5,6,4,8,9,2,3,7,2,7,6,5,9,8,9]
tree=[[L[9*i+3*j:9*i+3*j+3] for j in range(3)] for i in range(3)]
visited=set(); cuts=[]
def mx(node,a,b,idx):
    v=-math.inf
    for k,c in enumerate(node):
        w=mn(c,a,b,idx+[k]) if isinstance(c,list) else c
        if not isinstance(c,list): visited.add(tuple(idx+[k]))
        v=max(v,w)
        if v>=b: cuts.append((tuple(idx),v,b)); return v
        a=max(a,v)
    return v
def mn(node,a,b,idx):
    v=math.inf
    for k,c in enumerate(node):
        v=min(v,mx(c,a,b,idx+[k]))
        if v<=a: cuts.append((tuple(idx),v,a)); return v
        b=min(b,v)
    return v
root=mx(tree,-math.inf,math.inf,[])
mins=[min(max(m) for m in t) for t in tree]
print('P7 MIN values',mins,'root',root,'cuts',cuts,'leaves visited',len(visited))
print('P7c forcing MIN: best =',max(max(max(m) for m in t) for t in tree)-2,'vs',root)

# figure
fig,ax=plt.subplots(figsize=(10,3.6),dpi=150); ax.axis('off')
xs=np.arange(27); maxx=[xs[3*k:3*k+3].mean() for k in range(9)]; minx=[np.mean(maxx[3*k:3*k+3]) for k in range(3)]; rx=np.mean(minx)
for k in range(9):
    for j in range(3):
        i=3*k+j; vis=(k//3,k%3,j) in visited
        ax.plot([maxx[k],xs[i]],[2,1.15],color='0.3' if vis else '0.8',lw=1,ls='-' if vis else ':')
        ax.text(xs[i],1.0,str(L[i]),ha='center',va='top',fontsize=11,color='black' if vis else '0.7')
    mv=max(tree[k//3][k%3]); cut=any(c[0]==(k//3,k%3) for c in cuts)
    ax.plot([minx[k//3],maxx[k]],[3,2.15],color='0.3',lw=1)
    ax.text(maxx[k],2,'%d'%mv if not cut else '>=%d'%[c for c in cuts if c[0]==(k//3,k%3)][0][1],ha='center',va='center',fontsize=10,
            bbox=dict(boxstyle='round',fc='#fde2c8' if cut else '#dbe9f6',ec='none'))
for m in range(3):
    ax.plot([rx,minx[m]],[4,3.15],color='#c0392b' if m==2 else '0.3',lw=2.5 if m==2 else 1)
    ax.text(minx[m],3,'MIN %d'%mins[m],ha='center',va='center',fontsize=11,bbox=dict(boxstyle='round',fc='#e8e8e8',ec='none'))
ax.plot([minx[2],maxx[6]],[3,2.15],color='#c0392b',lw=2.5); ax.plot([maxx[6],xs[19]],[2,1.15],color='#c0392b',lw=2.5)
ax.text(rx,4,'MAX %d'%root,ha='center',va='center',fontsize=12,bbox=dict(boxstyle='round',fc='#f6d5d1',ec='none'))
ax.text(-0.5,4.3,'Red: minimax path. Orange MAX nodes: beta cut (grey dotted leaves are never evaluated).',fontsize=9)
ax.set_xlim(-1,27); ax.set_ylim(0.5,4.5); plt.tight_layout(); plt.savefig('figures/alphabeta.png',facecolor='white')

# ---------- Problem 8: A*
E={('G','F'):5,('F','D'):3,('G','D'):9,('G','E'):2,('E','D'):8,('D','B'):5,('B','A'):1,('D','C'):3,('C','B'):1,('C','A'):4}
adj={}
for (u,v),c in E.items(): adj.setdefault(u,[]).append((v,c)); adj.setdefault(v,[]).append((u,c))
def astar(h):
    g={'A':0};par={'A':None};pq=[(h['A'],'A')];closed=set();order=[]
    while pq:
        f,u=heapq.heappop(pq)
        if u in closed: continue
        closed.add(u);order.append(u)
        if u=='G': break
        for v,c in adj[u]:
            if v not in closed and g[u]+c<g.get(v,math.inf): g[v]=g[u]+c;par[v]=u;heapq.heappush(pq,(g[v]+h[v],v))
    p=['G']
    while par[p[-1]]: p.append(par[p[-1]])
    return order,p[::-1],g['G']
print('P8 designed h:',astar(dict(A=10,B=5,C=0,D=0,E=0,F=10,G=0)))
# ---------- Problem 14
M=np.array([[40,5,5],[4,35,11],[2,8,40]]);p=np.diag(M)/M.sum(0);r=np.diag(M)/M.sum(1);f=2*p*r/(p+r)
print('P14 precision',p.round(3),'F1',f.round(3),'macro F1 %.4f'%f.mean(),'micro recall %.4f'%(np.trace(M)/M.sum()))
# ---------- Problem 16
R=np.array([[5,3,np.nan,1],[4,np.nan,3,2],[1,1,5,5],[np.nan,np.nan,5,4]]);mu=np.nanmean(R,1)
def sim(u,v):
    m=~np.isnan(R[u])&~np.isnan(R[v]); a=R[u,m]-mu[u]; b=R[v,m]-mu[v]; return a@b/np.sqrt(a@a*(b@b))
s2,s3=sim(0,1),sim(0,2); print('P16 sims',s2,s3,'prediction',mu[0]+(s2*(R[1,2]-mu[1])+s3*(R[2,2]-mu[2]))/(abs(s2)+abs(s3)))
# ---------- Problem 15: Gram matrix of k2 on (black, black|white, white)
G=np.array([[1,1,0],[1,1,1],[0,1,1]]);print('P15 f^T G f',np.array([1,-1,1])@G@np.array([1,-1,1]))