50 kdb+/q questions Models (OpenRouter AI reference) --> Scores --------------------------------------------------------------------------------------------------------------------- Grok 4 ("x-ai/grok-4") --> 112.75 / 134 = 84.14 % Sonnet Claude 4 ("anthropic/claude-sonnet-4") --> 104.5 / 134 = 77.99 % Gemini 2.5 Pro ("google/gemini-2.5-pro"): --> 101 / 134 = 75.37 % Deepseek ("deepseek/deepseek-r1-0528"): --> 101 / 134 = 75.37 % Grok3 ("x-ai/grok-3"): --> 94.5 / 134 = 70.52 % Kimi K2 ("moonshotai/kimi-k2") --> 84.25 / 134 = 62.87 % GPT-4.1 ("openai/gpt-4.1"): --> 75.5 / 134 = 56.34 % GPT-4o ("openai/gpt-4o-2024-11-20") --> 70 / 134 = 52.54 % GPT-3.5-Turbo ("openai/gpt-3.5-turbo-0613") --> 49 / 134 = 36.57 % GPT-4o-mini ("openai/gpt-4o-mini"): --> 30.5 / 134 = 22.76 % ---------------------------------------------------------------------------------------------------------------------------------------------------------- Q1) Using kdb+/q - create a list of 10 random numbers from 10 to 20 (easy - 2 mark) --> 10+10?11 --> 1 point - generating a 10 random item list (e.g. 10?11) --> 1 point - bounds of list is between 10 and 20 Results: --> Sonnet Claude 4: (2/2) - correct (10 + 10?11 or float - 10+10?10.0) --> Gemini 2.5 Pro (2/2) - correct (10 + 10?11) --> Grok3: (2/2) - correct (10?10+til 11) --> Deepseek: (1.5/2) - incorrect output on list --> 10 + (-10)?11, claims duplicates are allow for -10?11 (false) --> GPT-4o-mini: (0/2) - incorrect (10 + 10 * floor rand 10) --> GPT-4.1 (2/2) - correct (10+10?11) --> GPT-3.5-Turbo (2/2) - correct (show 10?10+10?11 --> 17 17 18 19 15 15 15 13 20 15), fairly brief in its answer, code works but isn't the best --> Grok 4 : (1.5/2) - correct (10 + 10?11) --> however, some incorrect info in other examples shown (e.g. (til 11) + neg[10]?10) --> length error) --> Kimi K2: (0/2) - incorrect (-10?10 20) --> length error in reality but claims to make desired list --> GPT-4o: (2/2) - correct (10 + 10?11) Q2) Using kdb+/q - use the scan adverb to return the "Times Tables" from 1 to 10 (easy - 2 marks) --> {x+1+til[10]}\[9;1+til[10]] --> 1 point - returning correct time table --> 1 point - uses scan adverb Results: --> Sonnet Claude 4: (0/2) - (1+til 10) */ 1+til 10 (incorrect) --> only makes one list with the wrong values --> Gemini 2.5 Pro (1/2) - +\10#enlist 1+til 10 (syntax error) (1+til 10) */: 1+til 10 --> each-right works but doesn't use scan --> Grok3: (1/2) - 1+til 10 scan {x * 1+til 10} \ 1 (syntax error) {x * 1+til 10} each 1+til 10 --> each method works but doesn't use scan --> Deepseek: (0/2) - last { x, enlist y * 1+til 10 } \ [1+til 10; ()] --> incorrect, output = () --> GPT-4o-mini: (0.5/2) - {x * til 10} each 1+til 10 --> doesn't use scan, grid has 0 column in it --> GPT-4.1 (1/2) - */:\1+til 10 (1+til 10)*/:(1+til 10) {*/:\x} each (1+til 10) --> incorrect, syntax error using scan, each-right works --> GPT-3.5-Turbo (0/2) - {x*y}'[1+til 10]'1+til 10 --> incorrect, doesn't use scan --> Grok 4 : (1.5/2) - incorrect (+\10#enlist 1+til 10) --> syntax error, need +\ in brackets then it works --> Kimi K2: (2/2) - correct ({x+1+til 10}\[10;1+til 10]) --> GPT-4o: (0/2) - incorrect (t:(1 + til 10); m:/:t; m) --> syntax uses over Q3) Using kdb+/q - write a function that calculate factorial Ex 5!=5*4*3*2*1=120 - f[5] should return 120 (easy - 1 mark) --> f:{(*/) 1+til[x]} --> f:{prd 1+til x} --> 1 point - calculates the correct factorial Results: --> Sonnet Claude 4: (1/1) - correct --> f:{prd 1+til x} --> Gemini 2.5 Pro (0.5/1) - needs brackets around iterative approach */ --> f: {*/ 1 + til x} --> Grok3: (1/1) - Recursive apporach works --> f:{$[x<=1;1;x*f[x-1]]} --> Deepseek: (1/1) - correct --> f:{$[x<0;0N;prd 1+til x]} --> GPT-4o-mini: (0/1) - incorrect, syntax is off --> f:{x<2: 1; x*f[x-1]} --> GPT-4.1 (1/1) - correct --> f:{prd 1+til x} --> GPT-3.5-Turbo (1/1) - correct --> f: {prd 1+til x} --> f[5] = 120 --> Grok 4 : (1/1) - correct --> f:{prd 1+til x} --> Kimi K2: (1/1) - correct --> f:{prd 1+til x} --> GPT-4o: (1/1) - correct --> recursive solution (f:{[n] if[n=0 or n=1; :1]; :n * f[n-1];}) Q4) Using kdb+/q - Create a table that has the sym column as a list of symbols with UBS being the third item for some of the rows. Write a qSQL query returning only rows that have UBS has the third item in the list for the sym column. (medium - 3 marks). --> tab: ([] sym: (`TSLA`UBS`GOOGL`DI;`TSLA`DI`UBS`GOOGL;`DI`GOOGL`UBS`TSLA); price:3?20f) --> select from tab where sym[;2] in `UBS // Solution 1 --> select from tab where `UBS in 'sym[;2] // Solution 2 --> 1 point - using qSQL or functional statement to do query --> 1 point - outputs without error --> 1 point - filtering for third item to be `UBS Results: --> Sonnet Claude 4: (3/3) - correct // Create sample data with sym column as lists of symbols t:([] id:1 2 3 4 5 6; sym:(`AAPL`MSFT`UBS`GOOGL; `IBM`TSLA`AMZN; `JPM`GS`UBS`BAC`WFC; `ORCL`SAP`UBS; `META`NFLX`NVDA; `C`JPM`UBS`GS); price:100.5 200.3 150.7 300.2 250.8 180.4; qty:100 200 300 150 250 175) select from t where `UBS=sym[;2] --> Gemini 2.5 Pro (1/3) - incorrect, uses qSQL but type error trade:([time: .z.p + til 5; sym: (`IBM`GS`UBS`MSFT; `CS`UBS`JPM; `BAC`C`UBS`HSBC; `GOOG`AAPL`AMZN; `MS`DB); px: 101.5 240.1 35.2 1850.5 45.9; sz: 100 250 500 50 1000 ]) select from trade where `UBS = .[;2;`] each sym --> Grok3: (1/3) - incorrect, uses qSQL but incorrect syntax in making table // Create a table with sym column as a list of symbols t: table ( id: 1 2 3 4 5; sym: (`AAPL`GOOGL`UBS`MSFT`TSLA;`FB`AMZN`JPM`CSCO`INTC; `IBM`ORCL`UBS`SAP`DELL;`C`BAC`GS`JPM`WFC; `AMD`NVDA`UBS`QCOM`MU) ) // Query to select rows where UBS is the third item in the sym list select from t where sym[;2]=`UBS --> Deepseek: (2.5/3) - nearly correct, qSQL should be sym[;2] // Create the table with sample data t: ([]id: 1 2 3 4;sym: (`A`B`C`D;`X`Y`UBS`Z;`APPL`MSFT`UBS; `UBS`GS`JPM`C)) // Query to select rows where UBS is the third item in sym select from t where sym[2] = `UBS --> GPT-4o-mini: (1/3) - incorrect // Create the table with the sym column containing lists of symbols t: (`id`sym)!(0 1 2 3 4; (1 2 `AAPL`GOOG`UBS`MSFT; 2 3 `TSLA`UBS`NFLX`AMZN; 3 4 `FB`AAPL`UBS`TSLA; 4 5 `UBS`GOOG`NFLX`AAPL; 5 6 `AAPL`MSFT`NFLX`AMZN)) // Query to return only rows with UBS as the third item in the sym column result: select from t where 2 = count each sym, sym[2] = `UBS --> GPT-4.1 (2/3) - qSQL gives type error tbl: flip `id`sym!(1 2 3 4 5; (`AAPL`GOOG`UBS`MSFT;`MSFT`GS`BARC;`DB`ETF`UBS`GS;`C`JPM`AAPL;`CITI`MSFT`UBS)) select from tbl where sym 2 = `UBS --> GPT-3.5-Turbo (1.5/3) - incorrect, missing a bracket, type error even if added // Create table table: ([] sym: (("AAPL";"GOOGL";"UBS";"MSFT"); ("TSLA";"AMZN";"FB";"UBS"); ("NFLX";"NVDA";"INTC";"UBS"); ("SPY";"QQQ";"DIA";"UBS"); ("XOM";"C";"BAC";"UBS")) // Query to filter rows with UBS as the third item in the sym list select from table where sym[2] = `UBS --> Grok 4 : (1.5/3) - incorrect, table works but type error on query t:([] sym: (enlist `AAPL; (`GOOG`MSFT`UBS); (`IBM`JPM`C`BAC); (`GS`UBS); (`VOD`BCS`UBS`RBS)) ) select from t where {$[count[x]>2;x[2];``]}each sym=`UBS --> Kimi K2: (1/3) - incorrect, length error in creating table, query is almost correct tbl:([] id:10?`3; val:10?100f; sym:(`AIG,`CIT,`UBS,`GS), 5?`8, 4?`6) select from tbl where sym[2]=`UBS --> GPT-4o: (1.5/3) - incorrect, table is made but query gives a length error // Create a table with a `sym` column which is a list of symbols tbl: ([] sym: (`AAPL`GOOG`UBS; `MSFT`UBS`TSLA; `UBS`NFLX`AMZN; `GOOG`META`UBS); price: 100 200 300 400); // Select rows where UBS is the third item in the list for the `sym` column result: select from tbl where "UBS"=3#'sym Q5) Using kdb+/q - Generate a 10 x 10 grid of random numbers from -9 to 9. Ensure each row of grid is a random list of numbers. (easy - 3 marks) --> 10 cut -9+100?19 --> 1 point - creating 10 x 10 grid --> 1 point - numbers in grid are between -9 to 9 --> 1 point - random number generation for each row of grid Results: --> Sonnet Claude 4: (2/3) - 10 10#-9+19?100 --> incorrect, grid is not between -9 to 9 --> Gemini 2.5 Pro (3/3) - { (10 ? 19) - 9 } each til 10 --> correct --> Grok3: (3/3) - 10 10 # (19 ? 19) - 9 --> works, not the best optimized --> Deepseek: (0/3) - -9 + 10 ?' 19 --> incorrect, 1x10 list --> GPT-4o-mini: (0/3) - {10?(-9..9)} each til rows; --> incorrect, syntax error --> GPT-4.1 (3/3) - 10 10#100?(-9+til 19) --> correct --> GPT-3.5-Turbo (0/3) - {10?19i)-9} each til 10 --> incorrect, syntax error --> Grok 4 : (2/3) - grid: 10 10 # -9 + 100?19 --> somewhat correct, it is possible for each row to have duplicates --> Kimi K2: (0/3) - show g:10?(-9 + til 19)each 10 --> incorrect --> GPT-4o: (0/3) - ({-9 + floor 19 * rand[10]}'[10#()]) --> incorrect Q6) Using kdb+/q - create an unkeyed trade table then key the sym and side column (easy - 1 point): --> trade: ([] time: asc .z.d+3?.z.t; sym: upper 3?`3; price:3?100f; size:3?50;side: 3?`buy`sell) --> `sym`side xkey trade --> 1 point - create table & keying the correct columns by using the xkey command Results: --> Sonnet Claude 4: (1/1) - correct n:1000 trade:([] time:09:30:00.000 + asc n?06:30:00.000; sym:n?`AAPL`GOOGL`MSFT`TSLA`AMZN; side:n?`buy`sell; size:100*1+n?10; price:100+n?50.0; exchange:n?`NYSE`NASDAQ`BATS) trade_keyed:`sym`side xkey trade --> Gemini 2.5 Pro (1/1) - correct, makes unkeyed table and uses xkey command --> Grok3: (1/1) - correct, makes unkeyed table and uses xkey command --> Deepseek: (1/1) - correct, makes unkeyed table and uses xkey command --> GPT-4o-mini: (0.5/1) - incorrect, doesn't make unkeyed table right but xkey command works // Step 1: Create a sample trade table trades: (`time`sym`side`qty`price) ! ( (1 2 3 4 5) + 2023.10.01D00:00:00.000 + til 5, // timestamps `AAPL`AAPL`GOOG`MSFT`TSLA, // symbols `buy`sell`sell`buy`buy, // sides 100 150 200 250 300, // quantities 150.25 2750.50 2800.00 299.99 740.00 // prices ) // Step 2: Key the table by `sym` and `side` keyedTrades: `sym`side xkey trades --> GPT-4.1 (0.5/1) - creation of unkeyed table key needs ticks for each column (e.g. `time`sym`price`size`side) // 1. Create a typical trade table trade:flip `time sym price size side! (2024.06.12D09:30:00 09:31:05 09:32:10 09:32:15; `AAPL `GOOG `AAPL `AAPL; 190.2 2800 190.3 190.4; 100 20 200 50; `B `S `B `S) // 2. Key the table by sym and side kt:trade xkey `sym`side --> GPT-3.5-Turbo (1/1) - correct trade:([] time:10:00:00 10:01:00 10:02:00; sym:`AAPL`IBM`GOOG; side:`BUY`SELL`BUY; price:100.0 150.0 200.0; size:100 200 150) trade_keyed:`sym`side xkey trade --> Grok 4 : (0.75/1) - correct, however upsert should be used as data is added row by row trade:([] time:`time$(); sym:`symbol$(); side:`symbol$(); price:`float$(); qty:`int$()); `trade insert ((09:30:00.000; `AAPL; `buy; 150.5; 100i);(09:31:00.000; `GOOG; `sell; 2500.0; 50i); (09:32:00.000; `AAPL; `sell; 149.8; 200i);(09:33:00.000; `GOOG; `buy; 2495.5; 75i);(09:34:00.000; `MSFT; `buy; 300.2; 150i);(09:35:00.000; `MSFT; `sell; 299.9; 100i)); trade:`sym`side xkey trade --> Kimi K2: (1/1) - correct trades:([] time: .z.p + `second$til 5; sym: `A`B`C`D`E; side: `buy`buy`sell`buy`sell; price: 98.1 102.4 99.5 101.0 100.3; size: 100 150 200 120 90); trades: `sym`side xkey trades; --> GPT-4o: (1/1) - correct trade: ([] sym: `AAPL`MSFT`GOOG`MSFT`AAPL`GOOG`MSFT`AAPL; side: `buy`sell`buy`buy`sell`sell`sell`buy; price: 101.2 56.8 1330.7 57.1 101.5 1332.1 56.7 101.3; size: 100 200 150 50 300 10 500 120); trade: `sym`side xkey trade Q7) Using kdb+/q, - Create a function that makes an n x n numerical identity matrix (medium - 3 marks) --> f:{`int$til[x]=/:til[x]} --> 1 point - square matrix is generated for all test cases (e.g. 1 to 10) --> 1 point - values match what the identity matrix is suppose to be --> 1 point - values are numerical (not Boolean or other datatypes) Results: --> Sonnet Claude 4: (2/3) - identity:{(til x)=\:(til x)} --> missing casting, but otherwise good --> Gemini 2.5 Pro (3/3) - makeIdentityMatrixLong:{[n] 0j + (til n) =/: til n} --> correct --> Grok3: (2/3) - identityMatrix:{[n] flip (til n)=/:til n} --> missing casting, flip doesn't change an identity matrix --> Deepseek: (3/3) - id: {1f*(til x)=/:til x} --> correct --> GPT-4o-mini: (0/3) - identityMatrix: {n: x; I: 0n!n x n; I +\: (i: til n; i)} --> incorrect, domain error --> GPT-4.1 (2/3) - identity:{(til x)=\:til x} --> missing casting --> GPT-3.5-Turbo (0/3) - idMatrix: {[n] mat: n#n#0; mat[til n * n] : 1; mat} --> incorrect, length error --> Grok 4 : (3/3) - identity:{[n] 1.0 * (til n) =\: til n } --> correct --> Kimi K2: (0/3) - mkIdent:{@[`float$n#0;n#1;0;(til n),'til n]} --> incorrect, syntax error, n is undefined --> GPT-4o: (0/3) - identityMatrix:{[n] n#(0b;1b)#\:til n} --> incorrect, output is column list Q8) Using kdb+/q, write a function that takes an integer as an input and returns the sum of the digits (medium - 2 marks) --> f:{sum 10 vs x} // Solution 1 (assumed input is always positive) --> f:{sum "I"$/: string x} // Solution 2 (assumed input is always positive) --> 1 point - splitting integer into its individual digits --> 1 point - returning the correct sum (inputs are all positive) Results: --> Sonnet Claude 4: (0.5/2) - sumDigits:{sum "j"$'string abs x} --> incorrect --> Gemini 2.5 Pro (2/2) - sumDigits: {[x] sum 10 vs abs x} --> correct --> Grok3: (0.5/2) - sumDigits:{[x] num:abs x; digits:"J"$string num; sum digits} --> incorrect --> Deepseek: (2/2) - f: {x: abs x; s: 0; while[x > 0; s+: x mod 10; x: x div 10]; s} --> correct, different method it seems --> GPT-4o-mini: (0/2) - sumDigits: {sum each (1+/:\: x) mod 10} --> incorrect --> GPT-4.1 (0/2) - sumOfDigits:{sum 0N$/:string abs x} --> incorrect, length error --> GPT-3.5-Turbo (0/2) - sumDigits:{sum each "." vs string x} --> incorrect, wrong output --> Grok 4 : (0.5/2) - sumDigits:{sum "J"$ each string abs x} --> syntax error --> Kimi K2: (0.5/2) - sumDigits:{sum 0i$'string x} --> type error --> GPT-4o: (0.5/2) - sumDigits:{sum 10 sv string x} --> type error, uses sv but should be vs, string isn't needed Q9) Using kdb+/q, - create a function that takes a basic datatype and outputs its name (e.g. Input = 2025.06.18, Output = `date) (medium - 2 marks) --> f:{[a] basic: (`short$neg[1 2, 4+til[16]]) ! (`boolean`guid`byte`short`int`long`real`float`char`symbol`timestamp`month`date`datetime`timespan`minute`second`time); basic[type a] } --> (f[2025.06.18]; f["m"]; f[0x00];f[7]; f[9f]; f[2025.06m]; f[.z.p]) (Output = `date`char`byte`long`float`month`timestamp) --> 1 point - dictionary mapping --> 1 point - correct output Results: --> Sonnet Claude 4: (0.5/2) - incorrect, type x returns short value, not symbol datatype definition getTypeName:{(`mixed`boolean`guid`nothing`byte`short`int`long`real`float`char`symbol`timestamp`month`date`datetime`timespan`minute`second`time)[type x]} getTypeName[2025.06.18] --> Gemini 2.5 Pro (1.5/2) - namespace shouldn't be .q since it is reserved for commands. If we change it to another non-reserved namespace it works .q.type.atomMap: -1 -2 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19h ! `boolean`guid`byte`short`int`long`real`float`char`symbol`timestamp`month`date`datetime`timespan`minute`second`time; getTypeName: {[x] .q.type.atomMap type x }; --> Grok3: (0.5/2) - incorrect, type error getTypeName:{[x] typeDict:( -1h!"boolean"; -2h!"guid"; -4h!"byte"; -5h!"short"; -6h!"int"; -7h!"long"; -8h!"real"; -9h!"float"; -10h!"char"; -11h!"symbol"; -12h!"timestamp"; -13h!"month"; -14h!"date"; -15h!"datetime"; -16h!"timespan"; -17h!"minute"; -18h!"second"; -19h!"time" ); typeDict[type x] } --> Deepseek: (2/2) - correct typeName: {t: abs type x; $[t=0; `mixed; t=1; `boolean; t=2; `guid; t=4; `byte; t=5; `short; t=6; `int; t=7; `long; t=8; `real; t=9; `float; t=10; `char; t=11; `symbol; t=12; `timestamp; t=13; `month; t=14; `date; t=15; `datetime; t=16; `timespan; t=17; `minute; t=18; `second; t=19; `time; `unknown] } typeName 2025.06.18 --> GPT-4o-mini: (0/2) - incorrect, not dictionary, switch is not a reserved function/command, type mapping is wrong typeName:{[x] // Get the type of the input t: type x; // Use a case expression to match types with their names switch[t; 0b; "boolean"; // Boolean 1b; "byte"; // Byte 2b; "short"; // Short 3b; "int"; // Int 4b; "long"; // Long 5b; "real"; // Real 6b; "float"; // Float 7b; "double"; // Double 8b; "char"; // Char 9b; "symbol"; // Symbol 10b; "timestamp"; // Timestamp 11b; "date"; // Date 12b; "datetime"; // Datetime 13b; "time"; // Time 14b; "month"; // Month 15b; "minute"; // Minute 16b; "second"; // Second 17b; "guid"; // GUID 18b; "list"; // List 19b; "table"; // Table 20b; "dictionary"; // Dictionary 21b; "keyed table"; // Keyed table default; "unknown" // Fallback for unknown types ] }; --> GPT-4.1 (0/2) - incorrect, wrong type mapping, no dictionary typeNames: ( -1 "boolean" 0 "guid" 1 "byte" 2 "short" 3 "int" 4 "long" 5 "real" 6 "float" 7 "char" 8 "symbol" 9 "timestamp" 10 "month" 11 "date" 12 "datetime" 13 "timespan" 14 "minute" 15 "second" 16 "time" 17 "enum" ) getTypeName: {typeNames type x} --> GPT-3.5-Turbo (0.5/2) - getDataTypeName:{[x] dataType:`boolean`byte`short`int`long`real`float`char`symbol`timestamp`month`date`datetime`timespan`minute`second dataTypeName:("boolean";"byte";"short";"int";"long";"real";"float";"char";"symbol";"timestamp";"month";"date";"datetime";"timespan";"minute";"second") if[type x in dataType; dataTypeName dataType?type x; ]; } ``` You can call this function with a basic datatype as input to get its name. For example: ```q q) getDataTypeName 2025.06.18 ---> missing semicolons in function, other issues as well with type lookup "date" --> Grok 4 : (2/2) - correct f:{ names:("mixed list";"boolean";"guid";"";"byte";"short";"int";"long";"real";"float";"char";"symbol";"timestamp";"month";"date";"datetime";"timespan";"minute";"second";"time"); if[not type[x]<0; '"input must be a basic atom"]; names neg type x }; f[2025.06.18] --> "date" --> Kimi K2: (0/2) - incorrect nameOfType:{[x] / pass any value m: " bg xhijefcspmdznuvtts"^.. / mnemonic->keyword lookup m .Q.t abs type x } / map type->name nameOfType 2025.06.18 --> GPT-4o: (1/2) - incorrect getTypeName: {typeNames: 0 ! "null boolean guid byte short int long real float char symbol timestamp month date datetime timespan minute second time";type:type x;typeNames[type]}; getTypeName 2025.06.18 Q10) Using kdb+/q, create a function that take the date as an input, and return the previous workday (medium - 2 marks). If date is a Saturday, Sunday, or Monday, it needs to return a Friday. If the date is Tuesday to Friday it returns the previous workday. --> f:{$[(d: x mod 7) in 0 1 2i; $[d=2i; x-3; $[d=1i;x-2;x-1]]; x-1]} // Solution --> 1 point - returning the correct date for Tuesday to Friday --> 1 point - returning the correct date for Saturday, Sunday, Monday Results: --> Sonnet Claude 4: (1/2) - goes 1 week back when date is Monday, Sunday, Saturday prevWorkday:{[dt] wd:dt mod 7; // Get day of week (0=Saturday, 1=Sunday, 2=Monday, ..., 6=Friday) $[wd in 0 1 2; // Saturday, Sunday, or Monday dt - wd + 6; // Go to Friday dt - 1 // Otherwise, go to previous day ] } --> Gemini 2.5 Pro (0/2) - incorrect, d.u is not defined getPrevWorkday:{[d] / Lookup vector for days to subtract. / Indexed by d.u (Sun;Mon;Tue;Wed;Thu;Fri;Sat) daysBack: 2 3 1 1 1 1 1; / Subtract the appropriate number of days based on the day of the week. d - daysBack d.u } --> Grok3: (1/2) - incorrect for weekend dates and Monday prevWorkday:{[dt] / Convert date to day of week (0=Saturday, 1=Sunday, ..., 6=Friday) dow:dt mod 7; / Calculate days to subtract based on day of week daysToSub: $[dow in 0 1 2; dow+2-5*(dow=2); 1]; / Return the date minus the calculated days dt - daysToSub} --> Deepseek: (2/2) - correct prevWorkday: {[d] dow: "j"$ d mod 7; // Convert day of week to integer: Sat=0, Sun=1, Mon=2, Tue=3, etc. offset: $[dow in 0 1 2; 1 + dow; 1]; // Calculate days to subtract d - offset // Subtract the offset to get the previous workday } --> GPT-4o-mini: (0/2) - incorrect, syntax error previousWorkday: { // Calculate day of the week (0 = Sunday, 1 = Monday, ..., 6 = Saturday) day: (x mod 7); // If the day is Saturday (6) or Sunday (0), return the previous Friday // If the day is Monday (1), return the previous Friday // If the day is Tuesday (2) to Friday (5), return the previous day day = 6 or day = 0 or day = 1: x - (day + 2) mod 7; // Go back to Friday day = 2 or day = 3 or day = 4 or day = 5: x - 1; // Just go back 1 day }; --> GPT-4.1 (0.5/2) - incorrect, d is undefined, even if it is the output is still wrong for most dates prevWorkday:{ dow:d mod 7; :d - $[dow=0; 3; / Monday -> Friday dow=6; 2; / Sunday -> Friday dow=5; 1; / Saturday -> Friday 1] / Tuesday-Friday -> previous day } --> GPT-3.5-Turbo (0/2) - incorrect, dayOfWeek depends on .z.D (not needed in this question) prevWorkday: {[date] dayOfWeek: .z.D mod 7; / get the day of the week for today's date prevDay: date; // Check if the day is a weekend or Monday if[dayOfWeek in 0 1 2; prevDay: date - 3]; // if weekend or Monday subtract 3 days // Check if the day is Tuesday to Friday if[dayOfWeek in 3 4 5 6; prevDay: date - 1]; // if Tuesday to Friday, subtract 1 day // Return the previous workday prevDay } --> Grok 4 : (2/2) - correct prevWorkday:{[dt] wd:dt mod 7; $[wd<3;dt - wd+1;dt - 1]} prevWorkday[2025.07.21] --> Kimi K2: (1.25/2) - incorrect, off for Sunday and Saturday f:{[dt] wd:"i"$dt mod 7; dt - $[wd in 0 1 2;3;1]} f each 2023.10.16 2023.10.17 2023.10.18 2023.10.19 2023.10.20 2023.10.21 2023.10.22 --> GPT-4o: (0/2) - incorrect, no else command in kdb+/q prevWorkday:{[d] // Get the weekday number (Monday = 0, ..., Sunday = 6) wd:1+mod[d-1970.01.01;7]; // Determine the previous workday if[wd=1; d-3]; // If Monday, return previous Friday else if[wd=7; d-2]; // If Sunday, return previous Friday else if[wd=6; d-1]; // If Saturday, return previous Friday else; d-1]; } prevWorkday[2023.10.16] Q11) Using kdb+/q - write a function that returns the following output given the following input f "abcdef" --> "AbCdEf" (medium - 2 marks) --> s:"abcdef" --> f:{[s] @[s;where 0=til[count[s]] mod 2; upper]} --> 1 point - converting every second letter to capital letter --> 1 point - returning updated full string as the final answer Results: --> Sonnet Claude 4: (0/2) - incorrect alternateCase:{upper[x] where 0=2 mod til count x} alternateCase "abcdef" --> "BC" --> Gemini 2.5 Pro (2/2) - correct / Function definition altCase:{[s] ?[0b = (til count s) mod 2; upper s; lower s]} / Example Usage altCase "abcdef" // Output = "AbCdEf" --> Grok3: (0.5/2) - list of results alternateCase:{[str] idx:til count str; / create index list [0 1 2 ...] res:idx mod 2; / 1 for odd positions, 0 for even (upper str res=1;lower str) res / if res=1 use uppercase, else lowercase } alternateCase "abcdef" --> "AbCdEf" --> Deepseek: (2/2) - correct mixedCase: { { $[x mod 2; lower y; upper y] }' [til count x; x] } mixedCase "abcdef" --> "AbCdEf" --> GPT-4o-mini: (0/2) - incorrect toggleCase:{[s]chars: enlist each s;toggled: {if even x: x; 1 = odd x: toUpper x; 0 = odd x: toLower x} each til count chars;raze toggled} toggleCase "abcdef" --> syntax error --> GPT-4.1 (0/2) - junk output toggleCase:{raze(upper;lower)@/:((til count x)mod 2),/:/:x} toggleCase "abcdef" --> GPT-3.5-Turbo (0/2) - incorrect toCamelCase:{[input] output:(""); for[i:0; i Grok 4 : (0/2) - incorrect f:{?[0=2!(til count x);upper x;lower x]} f["abcdef"] --> Kimi K2: (0/2) - incorrect f:{`$1 _ raze{x,1#upper x}'(1 0b) rotate/: string x} f `abcdef --> GPT-4o: (0/2) - incorrect alternateCase: {string upperLower}'[til count x] each enlist x} where upperLower:{(x mod 2) ^ (x mod 2)' upper lower} each til 2; x mod 21 handles alternatingrip Q12) Using kdb+/q - Create a table, t, with 1 column name containing 50 random numbers between 0 and 50. Add a column which will return yes or no based on whether or not the number is greater than 25 (medium - 2 points) --> t: ([] ranNums: 50?51) --> update greater25:?[ranNums > 25;`yes;`no] from `t --> 1 point - generating table with a column of 50 random numbers from 0 to 50 --> 1 point - adding new column that says yes or no to whether the random number in each row is greater than 25 Results: --> Sonnet Claude 4: (2/2) - correct --> t:([] name:50?51); t:update result:`yes`no name>25 from t --> Gemini 2.5 Pro (1/2) - length error --> t:([] num: 50?51); t: update over25: (`no`yes; num>25) from t --> Grok3: (1/2) - length error --> t:([] name:50?50f); t:update above25:?[name>25; "yes"; "no"] from t --> Deepseek: (2/2) - correct --> t: update greater: ?[name>25;`yes;`no] from ([] name: -50?51) --> GPT-4o-mini: (1/2) - incorrect, two separate random lists used --> t: flip `number`greaterThan25!(50?51; (50?51) > 25) --> GPT-4.1 (0.5/2) - rank error --> t: flip `name!((50)?51); t: update flag: $[name > 25; "yes"; "no"] from t --> GPT-3.5-Turbo (1/2) - column is from 0 to 49, greater column output is all nulls // Create table t with column name containing 50 random numbers between 0 and 50 t:([] name:50?50) // Add column with values 'yes' or 'no' based on whether number is greater than 25 update greater_than_25:{[x] if[x>25; `yes; `no]}each name from t --> Grok 4 : (2/2) - correct / Create table with 50 random integers (0 to 50 inclusive) in column 'name' t:([] name:50?51) / Add a column 'flag' with 'yes' (symbol) if name > 25, else 'no' (symbol) t:update flag:?[name>25;`yes;`no] from t / Show the table (or a sample of it) t --> Kimi K2: (2/2) - correct t: update flag:?[name>25;`yes;`no] from ([] name:50?51) --> GPT-4o: (1/2) - incorrect, update statement gives a rank error // Create the table with 50 random numbers between 0 and 50 t: ([] name: 50?51) // Add a flag column: "yes" if >25, otherwise "no" t: update flag: $[name>25; "yes"; "no"] from t // Display the resulting table t Q13) Using kdb+/q, create the Pascal's Triangle solution to terminate when a value of greater than 100 is reached in the triangle. (hard - 3 marks) --> {all[x<100]}{(+) prior x,0}\ 1 // Ans --> 2 points - creating the Pascal triangle solution (e.g. {(+) prior x,0}\[5;1]) --> 1 point - iteration ends once a value in the last list is greater than 100 Results: --> Sonnet Claude 4: (1/3) - nulls in pascal triangle, other issues pascal:{[maxVal] triangle:enlist 1 1; // Start with row 1: [1,1] row:1 1; // Current row while[maxVal >= max row; // Continue while all values <= maxVal row:1,{x+next x}[row],1; // Generate next row triangle,:enlist row; // Add row to triangle ]; triangle } // Generate Pascal's Triangle stopping when value > 100 result:pascal[100] // Display the result show result --> Gemini 2.5 Pro (1/3) - doesn't work, some correct aspects nextRow: {[prevRow] 1, (2 +' prevRow), 1} appendNextRow:{[triangle] triangle, enlist nextRow last triangle} pascal show {x,enlist 1,2+'last x}\[{all 100>=last x};(enlist enlist 1);{x,enlist 1,2+'last x}] --> Grok3: (0.5/3) - incorrect, minor correct aspects but too much code // Function to generate Pascal's Triangle until a value > 100 is found pascalTriangle:{[] // Initialize first row triangle:enlist 1; i:1; // Loop until we find a value > 100 while[not any any triangle>100; // Generate next row nextRow:0,({x+y}':triangle[i-1;til count triangle[i-1]-1;1+til count triangle[i-1]-1]),1; triangle,:enlist nextRow; i+:1; ]; triangle } // Display the triangle show pascalTriangle[] --> Deepseek: (3/3) - correct res:enlist 1; // Initialize with the first row [1] row:1; // Current row starting at row0 while[not any row>100; // Continue until a value >100 appears row:(0,row)+row,0; // Generate next row by shifting and adding res:res,enlist row // Append the new row to the result ]; res --> GPT-4o-mini: (0/3) - type error // Function to generate Pascal's Triangle until a value greater than 100 is reached pascalTriangle: { // Initialize the triangle with the first row triangle: 1 `int; // Start with the first row of Pascal's Triangle, which is [1] // Iterate to generate rows until a value greater than 100 is found while[1 = 1b; // Infinite loop, will break when the condition is met lastRow: last triangle; // Get the last row of the triangle // Generate the next row nextRow: 1 + (lastRow + (1, 1) each (0, lastRow)); // Create next row // Check if any value in the next row is greater than 100 if[any nextRow > 100; break 1b;]; // Exit loop if condition is met // Append the new row to the triangle triangle,: nextRow; // Add new row to triangle ]; // Return the completed triangle triangle }; // Call the function to generate Pascal's Triangle result: pascalTriangle[]; --> GPT-4.1 (1/3) - type error, some correct info // Function to build next Pascal's triangle row nextRow:{1, (x except first x) + (x except last x), 1} // Initialize with the first row row: 1 rows: enlist row // Build the triangle row by row while[ all row<=100; row: nextRow row; rows,::enlist row ]; // Print all generated rows (does not include the last row with >100) rows --> GPT-3.5-Turbo (0/3) - syntax error numRows: x; triangle: (1;1); result: (triangle); while[count result] 100); result }; --> Grok 4 : (0/3) - incorrect, assign error pascal100:{ next:{(0j,x)+(x,0j)}; rows:(); current: ,1j; done:0b; while[not done; rows ,: enlist current; done: any current>100j; if[not done; current: next current]; ]; :rows; } --> Kimi K2: (0/3) - incorrect, type error pascal:{stop:100;r:(1 0)#;while[max[r 0]<=stop;r,:({(x+0,y)+y};flip r)1];r:(r 0)1_;r:(r where (max'[r])<=stop) }; // remove any 101 glitch line pascal[] --> GPT-4o: (0/3) - incorrect, type error ascalTriangle:{[limit] t: enlist 1; / Initialize with the first row while[all t[-1]<=limit; / Continue while all values in the last row are <= limit t,: enlist raze 0,'t[-1],'0 + t[-1] / Compute the next row using previous row ]; t} / Generate Pascal's Triangle and terminate when any value exceeds 100 triangle: pascalTriangle 100; / Print the result triangle Q14) Using kdb+/q - Create the Fibonacci Sequence solution to terminate when the size of the list reaches a count of 10 (hard - 3 marks) --> {x,sum -2#x}\[{10 > count x}; 0 1] // Ans = 0 1 1 2 3 5 8 13 21 34 --> 2 points - creating the Fibonacci sequence (e.g. {x, sum -2#x}\[5;0 1]) --> 1 point - terminates once list count is greater than 10 Results: --> Sonnet Claude 4: (2.5/3) - fib5:{x,:sum -2#x}/[{10>count x};0 1] --> almost, {x, sum -2#x} --> Gemini 2.5 Pro (2/3) - fib10: 8 ({x, sum -2#x}) / 0 1j --> type error, no need for round brackets around function --> Grok3: (3/3) - fibonacci: {seq: 0 1; while[count[seq] < 10; seq: seq, sum -2#seq ];seq} --> correct --> Deepseek: (3/3) - 8 {x,sum -2#x}/0 1 --> correct --> GPT-4o-mini: (0/3) - fibonacci: {fibs: 0 1; while[count fibs < 10; {fibs,: last fibs + (fibs (-1));}];fibs}; --> infinite while loop --> GPT-4.1 (0/3) - infinite while loop fibs:1 1; while[count fibs < 10; fibs,:sum -2#fibs]; fibs --> GPT-3.5-Turbo (0/3) - t undefined (variable error fibonacci: {1_t, (+) ./: -2 t: @[til count t; ((count t)-1;count t)]} 10#fibonacci 1 1 --> Grok 4 : (2.75/3) - partially correct, missing brackets for count[x] as the script is read fro right to left fib:{x, sum -2#x}/[{count x<10};0 1] --> Kimi K2: (1/3) - incorrect, handle error 10{(x;sum -2#x)}/[1;1 1] --> GPT-4o: (0/3) - incorrect, infinite while loop // Define a Fibonacci function that generates the sequence until the list has 10 elements fibonacci: {fib: 0 1;while[count fib < 10; fib,: sum -2#fib];fib}; // Call the Fibonacci function to generate the sequence fibonacci[] Q15) Using kdb+/q - Find the largest palindrome that can be made from the product of two 3-digit numbers (hard - 3 marks). // Product of TWO 3-digit numbers --> 100 x 100 to 999 x 999 Solution 1 --> ops: 100_til 1000 --> cuts: ops */: ops --> max raze {[p] cuts[p] where 1b = all each x = reverse each x: 10 vs/: cuts[p]} each til 1000 // Ans = 906,609 Solution 2: --> l: distinct raze (900 + til 100)*/:(900 + til 100) --> max l where (string each l)~'reverse each string each l // ANS: 906,609 --> 1 point - creating list of possible values to filter through --> 1 point - returning largest palindrome Results: --> Sonnet Claude 4: (0/2) - domain error max (raze {x * y _ 100 + til 900} [;100 + til 900] each 100 + til 900) where isPalindrome each (raze {x * y _ 100 + til 900} [;100 + til 900] each 100 + til 900) --> Gemini 2.5 Pro (0/2) - rank error max p where {[n](string n) ~ reverse string n} each p:distinct {x*y} . (100+til 900) cross (100+til 900) --> Grok3: (2/2) - correct // Function to check if a number is a palindrome isPalindrome:{x~reverse x} // Convert number to string to check if it's a palindrome palindromeCheck:{isPalindrome string x} // Generate all products of two 3-digit numbers (100-999) products:{raze x*/:x} 100+til 900 // Find all palindromic products palindromes:products where palindromeCheck each products // Get the largest palindrome largestPalindrome:max palindromes // Find the pairs of 3-digit numbers that multiply to the largest palindrome pairs:{(x,y) where x*y=largestPalindrome} . (100+til 900;100+til 900) // Display results show "Largest palindrome: ",string largestPalindrome show "Pairs that multiply to it: ",string pairs --> Deepseek: (2/2) - correct a:100+til 900; / Generate 3-digit numbers (100 to 999) prod: raze a */: a; / Compute all products and flatten into a single list s: string prod; / Convert each product to a string pal: s ~' reverse each s; / Check if each string is a palindrome res: max prod where pal; / Find the maximum product that is a palindrome res / Return the result --> GPT-4o-mini: (0/2) - type error // Function to check if a number is a palindrome isPalindrome: { str: string x; str = raze each str } // Initialize variable to store the largest palindrome largestPalindrome: 0; // Loop through all combinations of 3-digit numbers (100 to 999) do[100; 1000; { do[100; 1000; { prod: x*y; // Check if the product is a palindrome and greater than the current largest palindrome largestPalindrome: max(largestPalindrome; prod; (isPalindrome prod) * prod) }] }] largestPalindrome ``` --> GPT-4.1 (0/2) - type error prod: raze {x*y} each 100+til 900 cross 100+til 900; ispal: {($x)~reverse $x}; palindromes: prod where ispal each prod; maxpal: max palindromes --> GPT-3.5-Turbo (0.5/2) - type error, did make a list to filter through but were not all products of 3 digit values isPalindrome:{reverse x~x}; largestPalindrome:0; range:reverse til 100 * 100; {maxPalindrome:{largestPalindrome|max x where isPalindrome x}each x}range; largestPalindrome --> Grok 4 : (1.5/2) - incorrect, works once isPal variable s is defined from the right side isPal:{(s:string x)~reverse s}; n:100+til 900; prods:distinct raze {x*n where n>=x} each n; max prods where isPal each prods --> Kimi K2: (0.5/2) - incorrect, type error prod: {x */: y} [100+til 900] [100+til 900] flatProd: raze prod isPal: {x = reverse x} @ string pProds: flatProd where isPal flatProd largestPal: max pProds largestPal --> GPT-4o: (2/2) - correct / Function to check if a number is a palindrome isPalindrome: {x:string x; x~reverse x} / Generate all products of two 3-digit numbers (100 to 999) products: raze {x*y}[100+til 900;] each (100+til 900) / Filter products to get only palindromes palindromes: products where isPalindrome each products / Find the maximum palindrome maxPalindrome: max palindromes maxPalindrome Q16) What does this q code do and what is the output? (medium - 6 points)? --> {x*2}\[{x<500};1] --> 4 point - info about what each parameter does 1) 1 point: {x*2} - output is multiplied by 2 each iteration 2) 1 point: \ - usage of the scan accumulator iterator 3) 1 point: {x<500) - checks the last output to see if it is less than 500 and if not iteration stops) 4) 1 point: 1 - iteration starts with x = 1 and ends with 512 --> 1 point - description of q code being a while loop --> 1 point - correct output (e.g. 1 2 4 8 16 32 64 128 256 512) Results: --> Sonnet Claude 4: (3/6) - breakdowns some key concepts, doesn't give an output. ignores \ (e.g. {x*2}[{x<500};1]) then claims q code is incorrect --> Gemini 2.5 Pro (5/6) - says scan (\) is over (/) but otherwise correct --> Grok3: (3/6) - ignores (\) like above, says it will output without it --> Deepseek: (3/6) - ignores (\) like above, type error, --> GPT-4o-mini: (2/6) - says q code only doubles even numbers --> GPT-4.1 (3/6) - ignores \ (e.g. {x*2}[{x<500};1]) and calls q code flawed --> GPT-3.5-Turbo (2/6) - This q code multiplies the value of `x` by 2 if the value of `x` is less than 500. If the value of `x` is less than 500, the output will be `x*2`. If the value of `x` is greater than or equal to 500, the output will be the value of `x` itself. --> Grok 4 : (4/6) - incorrect Based on the syntax, the given code would produce a 'rank (or similar) error if executed as-is in q. I believe this is likely intended to be `{x*2}/[{x<500};1]` (with the over adverb `/` for conditional iteration, equivalent to a while loop). ### What It Does - It starts with the value `1`. - It repeatedly doubles the current value (i.e., applies `{x*2}`) as long as the current value `<500` (i.e., while `{x<500}` evaluates to true). - It stops as soon as the current value is `>=500`. - It returns the final value (the first power of 2 that is `>=500`). This is equivalent to the following pseudocode: ``` z = 1 while (z < 500) { z = z * 2 } return z ``` ### Output 512 If this doesn't match what you intended or if the code is exactly as provided without `/`, provide more context (e.g., full script or error details) for further analysis. ### References - [Adverbs in q (including while-style iteration)](https://code.kx.com/q/ref/adverbs/) - [Control structures in q](https://code.kx.com/q/basics/control/) --> Kimi K2: (4/6) - incorrect The expression ```q {x*2}[{x<500};1] ``` is ***invalid*** in q for two reasons: 1. A lambda **cannot** be applied to two separate arguments with ordinary juxtaposition (`[…;…]` only works on built-ins or explicitly declared multi-argument functions). 2. Even syntactically fixed, the lambda `{x*2}` only takes **one** argument, yet you are trying to feed *two* (`{x<500}` and `1`). Therefore the code throws an error (`'rank`) or `'type` depending on the exact parse attempt. ### How to do what you probably intended | What you probably want | Correct q code | Output | |---|---|---| | Keep doubling while the value is < 500 | `{x*2}/[{x<500};1]` (fold-converge) | 512 - the first value ≥ 500 produced by successive doubling (1→2→4→8→16→32→64→128→256→512). | | Apply the doubling function only once | `{x*2}[1]` or simply `{x*2} 1` | 2 | But **as written**, the fragment `{x*2}[{x<500};1]` does **nothing useful** and signals an error. --> GPT-4o: (4/6) - incorrect, q code I gave is misinterpreted by model with the missing backslash scan accumulator To interpret the q code `{x*2}[{x<500};1]`, we need to break it down step by step. q is a language primarily used with the kdb+ database, and it's known for being very concise. ### Explanation 1. **Understanding `{x*2}`**: - This is a lambda function (anonymous function) in q. - It takes one argument, `x`, and returns `x*2` (the value of `x` multiplied by 2). 2. **Understanding the call `[expr; arg]`**: - In q, you can invoke a function using square brackets: `[argument1; argument2; ...]`. Arguments are passed in order. - Here, the function `{x*2}` is being called, and the arguments are: - `expr`: `{x<500}` - `arg`: `1` 3. **Substituting into `{x*2}`**: - The first argument passed to `{x*2}` is `{x<500}`, which is another function. - The value of `1` is passed as the argument `x` to this function. 4. **Evaluating `{x*2}`**: - The function `{x*2}` takes its argument and doubles it. - However, the first argument provided (`{x<500}`) is a *function*, not a number, and attempting to multiply a function by `2` in q will throw an error. ### Result: - This q code will produce an **error** because the `{x*2}` function cannot process `{x<500}` as an argument since it is a function and not a numerical value. Functions in q cannot be directly multiplied or operated on in this way. Would you like to clarify or modify this q code to achieve a specific result? Let me know! Q17) In kdb+/q, list out the traditional components of a vanilla tickerplant system (medium - 8 points) --> 1 point for each of the seven components --> Data Feed --> Feedhandler (FEED) --> Tickerplant (TP) --> Real-time Subscribers/Engines (RTE) --> Historical Database (HDB) --> Real-time Database (RDB) --> Gateways (GW) Results: --> Sonnet Claude 4: (5/7) - [Tickerplant, RDB, HDB, Log Files, EOD processes, Feed Handler, Gateway] --> Gemini 2.5 Pro (5/7) - [Feedhandler, Tickerplant, RDB, HDB, Gateway] --> Grok3: (6/7) - [Feedhandler, TP, RDB, HDB, Log File, RTS, EOD Processes, Gateway] --> Deepseek: (5/7) - [Feedhandler, TP, RDB, HDB, Gateway, Transaction Log] --> GPT-4o-mini: (3/7) - [Tickerplant, Feed Handlers, Data Storage, Subscriber/Client Interfaces, Query Interfaces, Monitoring & Logging] --> GPT-4.1 (5/7) - [Feedhandler, Tickerplant, Realtime Subscribers, HDB, RDB] --> GPT-3.5-Turbo (5/7) - [Feedhandler, Publisher, Tickerplant, RDB, HDB, Subscriber, Query engine] --> Grok 4 : (6/7) - [FEED, TP, RDB, HDB, Gateway, WDB, IDB, tplog] --> Kimi K2: (7/7) - [Feeds, TP, Logs, RDB, HDB, Gateways, Data Feed] --> GPT-4o: (6/7) - [TP, RDB, HDB, FEED, Subscribers, Log File] Q18) In a kdb+ tickerplant system, explain what a slow subscriber is, how it can be detected, and what could be done to fix it? (medium - 3 points) --> Slow subscriber is a subscribe process (e.g. RTS/RTE) that is receiving data slower than it is being published by the tickerplant --> Can detect it by looking into .z.W (dictionary showing open handles ! (size of messages in the queue)) and looking into which handle has the largest size (usually that one is the slow subscriber) --> Could fix it by dropping the handle and re-establishing connection, increasing resources of TP (more CPU core, available RAM) or adding additional tick components like a chained TP --> 1 point: Explaining what a slow subscriber is --> 1 point: Viable methods in which a developer can detect it --> 1 point: Outlining possible methods to fix it Results: --> Sonnet Claude 4: (3/3) - A **slow subscriber** is a process that cannot keep up with the rate of incoming data from the tickerplant. When the tickerplant publishes updates faster than a subscriber can process them, messages queue up in the subscriber's IPC buffer. Detection [Monitor IPC Handle Statistics, Memory Usage Monitoring] Fix Issue [Optimize Message Processing, Implement Aysnchronous Processing, Selective Subscription, ] --> Gemini 2.5 Pro (3/3) - A **slow subscriber** is a client process that cannot read data from its TCP/IP buffer and process it as quickly as the tickerplant is sending it. Detection [using .z.W, monitor tickerplant memory] Fix Issue [manual disconnect of slow subscriber handle, auto-disconnect ] --> Grok3: (3/3) - A **slow subscriber** is one that processes data slower than the rate at which the tickerplant publishes it. Detection [Monitor Subscription Queue Size, Check for Backlog Alerts, Monitor Tickerplant Memory Usage] Fix Issue [Optimize Subscriber Code, Increase subscriber resources, Offload Processing] --> Deepseek: (3/3) - a **slow subscriber** is a downstream process (e.g., real-time database, analytics engine) that cannot process messages from the tickerplant as quickly as they are published. Detection [Tickerplant Monitoring, Subscriber Self-Monitoring, Log Analysis, Heartbeat Checks] Fix Issue [Build subscribers to handle peak load and use async patterns to avoid blocking] --> GPT-4o-mini: (3/3) - a "slow subscriber" refers to a client connection (such as a trading application, analytics tool, or monitoring system) that is processing incoming market data at a slower rate than it is being published by the tickerplant. Detection [Monitoring Lag & Latency, Heartbeat Intervals, Buffer Size Monitoring, Logging and Alerts] Fix Issue [Optimizing the Subscriber Application, Increasing resources, load balancing, batch processing, adjusting streaming parameters] --> GPT-4.1 (3/3) - A **slow subscriber** is a process or client that **cannot keep up with the rate of updates sent by the tickerplant**. This means its ability to process/consume incoming messages lags behind the TP's publishing speed. Detection [Monitoring TP Console, Monitoring kdb+ Internal Handles] Fix Issue [Optimize Subscriber, smaller batches, buffer size, unsubscriber slow clients] --> GPT-3.5-Turbo (3/3) - A slow subscriber in a kdb+ tickerplant system is a subscriber that is unable to keep up with the rate at which data is being published by the tickerplant. Detection [monitoring and alerting mecanism] Fix Issue [optimize subscriber hardware] --> Grok 4 : (3/3) - correct Slow Subscriber [subscriber process that cannot process incoming updates from the TP at the same rate they are being published] Detection [monitor .u.w dictionary, monitor input queue/buffer, track processing rate] Fix Issue [Optimize subscriber's code, scale resources, architectural changes, preventive measures] --> Kimi K2: (3/3) - correct Slow Subscriber [A **slow subscriber** is a client that cannot keep up with the rate at which the tickerplant publishes data.] Detection [looking into .z.W buffer size, subscriber-side detection .z.ts, logging and alerts] Fix Issue [dropping subscriber handle and re-connecting, optimize subscriber code, hardware upgrades ] --> GPT-4o: (3/3) - correct Slow Subscriber [ a **slow subscriber** is a process (or consumer) that is unable to keep up with the rate of real-time updates being published by the tickerplant.] Detection [monitor message backlogs, heartbeat mechanism, latency metrics] Fix Issue [optimize subscriber code, load balancing, hardware scaling, catch-up mechanism] Q19) In terms of kdb+/q Inter-process Communication, which .z namespaces will let me know if a message was sent synchronously or asynchronously? (easy - 2 points) --> .z.pg - value passed into the kdb+ session via synch request --> .z.ps - value passed into the kdb+ session via asynch request Results: --> Sonnet Claude 4: (2/2) - correct --> [.z.pg (synch) / z.ps (asynch)] --> Gemini 2.5 Pro (0/2) - incorrect --> mention of .z.pi --> Grok3: (2/2) - correct --> [.z.pg (synch) / z.ps (asynch)] --> Deepseek: (2/2) - correct --> [.z.pg (synch) / z.ps (asynch)] --> GPT-4o-mini: (0/2) - incorrect --> [.z.a (asynch) / .z.s (synch)] --> GPT-4.1 (2/2) - correct --> [.z.pg (synch) / z.ps (asynch)] --> GPT-3.5-Turbo (0/2) - incorrect --> [.z.ts (asynch) / .z.ns (synch)] --> Grok 4 : (2/2) - correct --> [.z.ps (asynch set), .z.pg(synch get)] --> Kimi K2: (2/2) - correct --> [.z.ps (asynch set), .z.pg (synch get)] --> GPT-4o: (0/2) - correct --> [.z.ps (synch), .z.pg (asynch)] Q20) List out the various methods table data can be saved down to disk in kdb+ (easy - 4 points) --> Flat table - entire table saved as one file (okay up to a few million rows) --> Splayed table - table saved as a folder with each column of that table saved as a file --> Partitioned Database - a series of splayed tables saved under one partitioned date (e.g. trade, quote, nbbo, order - all for the same trading day) --> Segmented Database - partitioned databases spread across different disk mounts --> 1 point for each of the 4 methods Results: --> Sonnet Claude 4: (4/4) - correct [Splayed Tables, Serialized Tables, Partitioned Tables, CSV Format, Text/Delimited Files, JSON, Segmented Tables] --> Gemini 2.5 Pro (3/4) - missing segmented database [Binary Flat File, Splayed Table, Partitoned Table (.Q.dpft), CSV] --> Grok3: (3/4) - missing segmented database [Flat File, Splayed Table, Partitioned Table, CSV, Text] --> Deepseek: (3/4) - missing segmented database [Binary Serialization, Splayed Tables, Partitioned Tables, Text/CSV Export, Compressed Serialization] --> GPT-4o-mini: (1/4) - missing info [CSV Files, Binary Files, Table Format, qdump, HDB & SDB Structures, Serialization, Append Mode] --> GPT-4.1 (3/4) - missing segmented database [save Command, .Q.sav, Spalyed & Partitioned Tables, using set, Text Export] --> GPT-3.5-Turbo (1/4) - missing info [Text files, Binary files, HDF5 files, Parquet files, Database files] --> Grok 4 : (4/4) - correct [flat, splayed, partitioned, segmented] --> Kimi K2: (4/4) - correct [one-table-per-file (flat), splayed, partitioned, segmented] --> GPT-4o: (4/4) - correct [binary table file (flat), partitioned database, splayed, CSV/Text, append, custom serialization] Q21) List all the methods that table joins can occur in kdb+ along with an example (easy - 9 points) 1) Vertical Join / Joining using comma (,) --> e.g. tab1, tab2 2) Horizontal Join / Joining using comma & tick (,') --> e.g. tab1, 'tab2 3) Left-Join (lj) --> e.g. lj[tab1;tab2] where tab1 = unkeyed, tab2 = keyed 4) Inner-Join (ij) --> e.g. ij[tab1;tab2] where tab1 = unkeyed, tab2 = keyed 5) Union Join (uj) --> e.g. uj[tab1;tab2] where each table can be unkeyed or keyed 6) Equi Join (ej) --> e.g. ej[`sym;trade;quote] 7) Plus Join (pj) --> e.g. pj[tab1;tab2] where tab2 is keyed and tab1 is unkeyed, keyed column can exists in both tables 8) Asof Join (aj / aj0) --> e.g. aj[`sym`time;trade;quote] (aj --> boundary time of trade, aj0 --> actual time of quote) 9) Window Join (wj / wj1) --> e.g. wj[windows;`sym`time;trade;(quote;(min;`ask);(max;`bid))] --> 1 point for each of the methods Results: --> Sonnet Claude 4: (6/9) - missing a few, examples show keyed joins as unkeyed tables [lj, ij, uj, pj, aj, wj, equi-join (using = in where clause)] --> Gemini 2.5 Pro (7/9) - missing horizontal join and pj [lj, ij, aj, ej, uj, joining through (,), cross-join (cj), wj/wj1] --> Grok3: (6/9) - examples shows both tables as keyed which is fine [ij, lj, uj, ej, aj, wj] --> Deepseek: (5.5/9) - some incorrect syntax and missing info [inner-join (ej), lj, ljf, aj, wj/wj1, pj, uj] --> GPT-4o-mini: (2/9) - mostly incorrect, tables show are really dictionaries syntax [inner-join (lj), left-join(lj), right-join(rj), outer-join(uj), semi-join(sj), anti-join(aj)] --> GPT-4.1 (4.5/9) - missing info and syntax issues [equi-join(,), ij, lj, rj, aj, ajf, uj, pj, except-join(ej), cross-join] --> GPT-3.5-Turbo (2/9) - missing info and syntax issues [inner-join(lj), outer-join(lj), left-join(lj), right-join(lj), cross-join (lj), semi-join(lj), anti-join(lj)] --> Grok 4 : (8/9) - [comma join (,), ej, lj, ij, pj, uj, upsert, aj, wj] --> Kimi K2: (6/9) - [lj, pj, aj, wj, uj, (,)] --> GPT-4o: (5/9) - [simple-join(,), ij, lj, right-join (rj), outer-join, aj, wj] Q22) List out all the reserved namespaces in kdb+ (easy - 6 points) - .Q -> utility functions - .q -> reserved commands for q programming - .m -> used to allow explicit allocation of optane memory (markup output for HTTP) - .j -> used to convert JSON files to q dictionaries - .h -> markup function used to convert files into various formats and for web-console display - .z -> system variables, and call hook backs (used a lot for IPC) --> 1 point for each reserved namespace Results: --> Sonnet Claude 4: (6/6) - correct [.q, .Q, .h, .j, .z, .m, .o, .s] --> Gemini 2.5 Pro (5/6) - missing .m [.q, .z, .h, .Q, .j, .p, .o, .s] --> Grok3: (5/6) - missing .m [.Q, .h, .j, .o, .q, .z] --> Deepseek: (5/6) - missing .m [.z, .h, .j, .Q, .q, .o, .s] --> GPT-4o-mini: (0/6) - incorrect [`::, `system, `user, `$] --> GPT-4.1 (6/6) - correct [.Q, .h, .z, .u, .p, .o, .k, .q, .m] --> GPT-3.5-Turbo (3/6) - missing a few namespaces [.Q, .h, .z, .s, .d, .j] --> Grok 4 : (5/6) - [.h, .j, .q, .Q, .z] --> Kimi K2: (5/6) - missing .m [.Q, .q, .z, .h, .j, .o, .s, .b] --> GPT-4o: (6/6) - [.q, .z, .h, .o, .j, .u, .Q, .K, .e, .p, .m] Q23) Name all the mapping iterators in kdb+ and give an example for each (easy - 6 points) * Mapping Iteration --> closest thing to for loops in kdb+ --> each, each-both, each-left, each-right, each-prior, each-parallel/ 1) each --> (e.g. reverse each (1 2; `a`b`c;"24") --> (2 1;`c`b`a;"42") 2) each-left (\:) --> (e.g. 3 4 5 6{x*y}\:5 --> 15 20 25 30) 3) each right (/:) --> (e.g. 5{x*y}/: 3 4 5 6 --> 15 20 25 30) 4) each prior (':) --> (e.g 0 +': 1 2 3 4 --> 1 3 5 7) 5) each both (') --> (e.g. 3#'("the";"brown";"bear") --> ("the";"bro";"bea")) 6) each-parallel (': or peach) --> used as multi-threading each (e.g (+\)peach(2 3 4;(5 6;7 8);9 10 11 12)) --> 1 point for each mapping iterator Results: --> Sonnet Claude 4: (5/6) - missing each-parallel --> [each, each-right (/:), each-left(\:), each-both('), each-prior(':), each-parallel (':)] --> Gemini 2.5 Pro (4/6) - missing each prior and each parallel --> [each, each-right (/:), each-left(\:), each-both(')] --> Grok3: (4/6) - missing each prior and each parallel --> [each, each-right (/:), each-left(\:), each-both('), scan (\), over (/)] --> Deepseek: (3/6) - missing 3 of them --> [each, each-right (/:), each-left(\:)] --> GPT-4o-mini: (1.5/6) - incorrect [each, each-right (/), each over] --> GPT-4.1 (3.5/6) - missing a few, syntax mistakes --> [each, each-left (\:), each-right (/:), each-prior (/:)] --> GPT-3.5-Turbo (1.5/6) - missing a lot, syntax mistakes --> [each, over, scan, prior, deltas, differ, ratios] --> Grok 4 : (5/6) - [each, each-left, each right, each-prior, each-parallel] --> Kimi K2: (4/6) - [each, each-left, each-right, each-prior, scan, over] --> GPT-4o: (1/6) - [each (/), each-prior(\)] Q24) How to I comment block in kdb+/q? (easy - 1 point) \ Block of comments here / --> 1 point - explaining/showing the above Results: --> Sonnet Claude 4: (0/1) - only shows comments for single lines, no comment blocking --> Gemini 2.5 Pro (1/1) - correctly shows block comments --> Grok3: (1/1) - correctly shows block comments --> Deepseek: (0/1) - only shows single line comments --> GPT-4o-mini: 0/1) - only shows single line comments --> GPT-4.1: (0/1) - only shows single line comments --> GPT-3.5-Turbo (0/1) - only shows single line comments (incorrectly uses backslash \ instead of forward slash /) --> Grok 4 : (1/1) - correct --> Kimi K2: (0.5/1) - incorrect [does /* */] --> GPT-4o: (0/1) - incorrect [claims there is no way to comment block and use single line comments] Q25) In kdb+/q, qSQL can use pass by reference and pass by value to add rows of financial data to a table. Which commands allow me to do so and what are the differences? (easy - 2 points) --> Pass by value (trade) - used for upserting value into a table, insert command will throw a type error --> pass by reference (`trade) - works for both insert and upsert, --> 1 point - highlighting upsert and insert commands for adding data to a table (IPC and apply to a function concepts use pass by ref/value) --> 1 point - explaining the key difference between them Results: --> Sonnet Claude 4: (0.5/2) - references insert for pass by reference, does a join when referring to pass by value (no mention of upsert) --> Gemini 2.5 Pro (0.5/2) - shows insert for pass by reference but mentions .Q.dpft for pass by value (incorrect) --> Grok3: (1.5/2) - insert doesn't take a table that is pass by value ### Key Commands for Adding Rows: `insert` and `upsert` 1. **`insert`**: - Used to append new rows to an in-memory table or a table on disk. - It operates by **pass by value** when you provide literal data or a computed result, or by **pass by reference** when you provide a symbol that refers to a table or data structure. - Syntax: `` `tableName insert data `` 2. **`upsert`**: - Used to either update existing rows or insert new rows into a table based on key columns (for keyed tables). - Like `insert`, it can operate by **pass by value** or **pass by reference**, depending on how the data is provided. - Syntax: `` `tableName upsert data `` --> Deepseek: (1.5/2) - doesn't show that insert throws an error for pass by reference ### Summary - Use **`insert`** for appending rows, with pass-by-reference behavior for in-memory tables and pass-by-value-like behavior for input data or disk writes. - Use **`upsert`** for updating or appending rows in keyed tables, with similar reference/value considerations. - Choose between in-memory and disk operations based on latency, persistence, and memory constraints, especially critical for financial data where speed and accuracy are paramount. --> GPT-4o-mini: (1/2) - mention of insert and upsert, pass by reference (upsert) / pass by value (insert) --> GPT-4.1 (1/2) - upsert should show it can work through pass by value ## **Key Differences** | Method | In-place? | Table changes immediately? | New table allocated? | Use-case | |------------------------|--------------------|---------------------------|---------------------|-------------------| | `,` (comma, concat) | No (value) | No (unless reassigned) | Yes | Ad hoc, immutable | | `upsert`/`insert` | Yes (reference) | Yes | No | Efficient, big data| - **Pass by value (`t, y`):** Good for small/temporary tables, functional programming style, safe (original table unchanged). - **Pass by reference (`insert`/`upsert`):** Efficient for large tables, recommended for real-time apps or when memory is important. --> GPT-3.5-Turbo (1/2) - insert (pass by value - but code shows pass by reference), upsert (pass by reference) --> Grok 4 : (2/2) - correct #### 1. `insert` - **Purpose**: Appends new rows to a table. It **fails** if the new rows contain duplicate keys (for keyed tables). Use this when you know the rows are new (e.g., appending real-time trades without duplicates). - **Syntax**: - Pass by reference: `insert[`tablename; newrows]` or ``tablename insert newrows`. - Pass by value: Not directly supported—you must use upsert for value-based appends (see below). However, you can simulate it by reassigning: `t: insert[t; newrows]` (but this is uncommon; use upsert instead). - **Return Value**: Indices of the inserted rows (useful for logging or verification). - **When to Use**: For pure appends (no updates). Efficient for on-disk tables via reference. #### 2. `upsert` - **Purpose**: Appends new rows or updates existing rows if keys match (for keyed tables). It "upserts" (update or insert). Use this for financial data where duplicates might occur (e.g., correcting a trade record). - **Syntax**: - Pass by reference: `upsert[`tablename; newrows]` or ``tablename upsert newrows` or ``:path/to/table/ upsert newrows` (for on-disk). - Pass by value: `upsert[tablevar; newrows]` or `tablevar upsert newrows`. - **Return Value**: The updated table (for pass by value) or the table name (for pass by reference, with the table modified in place). - **When to Use**: For appends that might involve updates. More flexible than `insert`. --> Kimi K2: (0.5/2) - only upsert mentioned --> GPT-4o: (1/2) - insert claims to work using pass by value ### Differences Between `insert` and `upsert` | Feature | `insert` | `upsert` | |------------------------|----------------------------------------------------|--------------------------------------------------| | **Execution** | Appends rows to a table pass-by-value | Combines updates/inserts directly pass-by-reference | | **In-place updates** | No (creates a new copy of the table internally) | Yes (directly updates the table in memory) | | **Usage** | Common with persistent tables or where appending | Useful for memory tables and for combining changes | | **Performance** | Slightly more overhead due to internal value updates | Generally faster for in-memory modifications | Q26) What are the 4 attributes in kdb+? (easy - 4 points) --> sorted (`s#) --> unique (`u#) --> parted (`p#) --> grouped (`g#) --> 1 point for each attribute Results: --> Sonnet Claude 4: (4/4) - correct --> Gemini 2.5 Pro (4/4) - correct --> Grok3: (4/4) - correct --> Deepseek: (3/4) - incorrect, called `p# --> partitioned --> GPT-4o-mini: (0/4) - incorrect [s=symbol, time, date, timestamp] --> GPT-4.1 (4/4) - correct --> GPT-3.5-Turbo (0/4) - incorrect [symbol, numerical, character, date & time] --> Grok 4 : (4/4) - correct --> Kimi K2: (4/4) - correct --> GPT-4o: (4/4) - correct Q27) In kdb+ tickerplant architecture, explain what the .u.sub function does in a tickerplant (medium - 2 points) --> .u.sub[x;y] where x = table name (pass by reference), y = list of symbols to filter for --> part of the u.q utillity script in Tick Architecture, used by the RDB and RTS to subscribe to a TP --> the new subscriber handle will be added to .z.W ( open handle ! size of byte message) --> 1 point - explaining what it is and which tick processes would typical use .u.sub --> 1 point - outlining the parameters Results: --> Sonnet Claude 4: (2/2) - In kdb+ tickerplant architecture, the `.u.sub` function is a core subscription mechanism that allows client processes to subscribe to data feeds from the tickerplant. (e.g. .u.sub[table;syms]) --> Gemini 2.5 Pro (2/2) - .u.sub` is the function a subscriber process calls on the tickerplant to subscribe to data for specific tables and symbols. h(".u.sub"; `trade; `IBM`GOOG) --> Grok3: (2/2) - the `.u.sub` function plays a critical role in managing subscriptions from downstream processes, such as Real-Time Databases (RDBs), Historical Databases (HDBs), or other client processes, to the tickerplant. .u.sub[`trade; `AAPL`GOOGL] --> Deepseek: (2/2) - .u.sub` enables clients to **register interest** in real-time data streams (e.g. .u.sub[table; syms]) --> GPT-4o-mini: (1/2) - The `.u.sub` function is used to manage subscriptions from clients to specific data streams (e.g. .u.sub[`AAPL]) --> incorrect parameters --> GPT-4.1 (1/2) - `.u.sub` function handles client subscriptions to the tickerplant (e.g. .u.sub[syms; tables]) --> parameters are swapped --> GPT-3.5-Turbo (1/2) -The `.u.sub` function in a tickerplant is a callback function that is triggered whenever a subscriber (e.g., a downstream process or query) subscribes to receive real-time market data updates from the tickerplant. --> doesn't state what the functions are --> Grok 4 : (2/2) - correct `.u.sub` is a function in the tickerplant that **handles subscription requests from downstream processes**. It is invoked remotely by a subscriber over its handle to the TP. For example, an RDB might execute something like this to subscribe: ```q // In the subscriber (e.g., RDB) h: hopen `::5050 // Open handle to TP on port 5050 schema: h(`.u.sub; `trade; `IBM`GOOG) // Subscribe to 'trade' table for symbols IBM and GOOG --> Kimi K2: (2/2) - correct `.u.sub` is the **standard subscription function** that every kdb+ **tickerplant** includes. It is exposed on port **5010 (or the port you start the TP on)** so that **real-time subscribers** (RDBs, CEP engines, GUI clients, …) can register for the tables and symbols they want to see going forward. What the vanilla source code does (from `$QHOME/tick/u.q`, trimmed): ```q / tp.q – subscription handler .u.sub:{[t;s] / t = table name (or `` for all), s = symbol list if[not t in .u.t; '"unknown table"]; / make sure table exists `.u.w upsert[`$(.z.w);$[t~`;0b;(t;s)]]; / remember this client wants this feed (t;$[t~`;value t;select from value t where sym in s]) / return (name;replay) } ``` --> GPT-4o: (1.5/2) - partially correct, missing table name in parameter ### Purpose of `.u.sub` The `.u.sub` function is typically invoked by clients (like a q process) that want to receive real-time updates from the tickerplant. Through this function, clients specify which data (e.g., stock symbols, tables, or other data subsets) they are interested in, and the tickerplant will then send updates for those subscriptions whenever relevant data changes occur. .u.sub[`;`sym1`sym2] Q28) In kdb+/q - Explain what functional select statement is and what it looks like? (easy - 3 points) --> method of querying a table, takes between 4 to 6 parameters --> ?[table;whereClause;byClause;returnClause;(index window); (aggregation)] --> 1 point - explaining it is used for querying a table --> 2 point - outlining the typical syntax, as well as the optional parameters Results: --> Sonnet Claude 4: (2.5/3) - ?[table; where_clause; group_by; select_clause] (e.g. ?[people; enlist (>; `age; 25); 0b; `name`age!`name`age]) --> no mention of optional parameters --> Gemini 2.5 Pro (2.5/3) - ?[tableName; whereClause; groupingClause; aggregationClause] (e.g. ?[trade; (); 0b; `sym`price!`sym`price]) --> no mention of optional parameters --> Grok3: (2/3) - ?[table; where_conditions; by_columns; select_columns] (.e.g. ?[t; enlist (>;`age;28); 0b; (::)]) --> should be (), no mention of optional parameters --> Deepseek: (2.5/3) - ?[data; conditions; groupings; aggregations] (.e.g. ?[`table; enlist (>; `price; 100); (); `price`price!(`price;`price)]) --> price shows up twice in return clause, no mention of optional parameters --> GPT-4o-mini: (0/3) - select from where --> calls qSQL functional statement --> GPT-4.1 (0.5/3) - select[projection; table; where; by; aggregation] (.e.g. select[; t; (enlist `price)!enlist (price t)>15; enlist `sym]) --> incorrect syntax --> GPT-3.5-Turbo (0/3) - table where condition (.e.g. stocks where price > 100) --> incorrect, bad qSQL --> Grok 4 : (2.5/3) - missing optional parameters ?[table; where_clauses; by_clauses; select_clauses] --> Kimi K2: (2/3) - missing optional parameters, syntax is slightly off --> GPT-4o: (1.5/3) - missing required and optional parameters, ?[table; whereClause; selectList] Q29) Using kdb+/q - Create a custom version of the rotation function command --> Input: x = "abc", y = 1 Output: "bca" (medium - 3 points) // custom_rotate["abc";1] --> "bca" custom_rotate: {_[y;x],#[y;x]} custom_rotate["abc";1] // Ans = "bca" custom_rotate["abc";2] // Ans = "cba" custom_rotate["abc";3] // Ans = "abc" --> 1 point - using drop and take commands --> 2 point - works for all test cases Results: --> Sonnet Claude 4: (0/3) - myrotate2:{[n;lst] len:count lst; if[0=len;:lst]; pos:len!(neg n);lst pos+til len} --> incorrect, error --> Gemini 2.5 Pro (3/3) - leftRotate: {[list; n] (n _ list) , n # list} --> Grok3: (0/3) - rotate:{[str;pos] len:count str; pos:pos mod len;if[pos<0; pos:len+pos]; (pos rotate str)} --> uses reserved function as name and command --> Deepseek: (0/3) - rot:{[x;y] :count x; if[n=0;:x];eff:y mod n;(eff _ x), eff#x} --> returns number --> GPT-4o-mini: (0/3) - rotate:{[x;y] len: count x; y: y mod len; x @\: (y, 0), x @\: (0, y)} --> uses reversed command as variable, type error --> GPT-4.1 (1/3) - rotate:{[x;y] (x y _drop),(x y#)} --> type error, uses drop and take --> GPT-3.5-Turbo (0.5/3) - rotate: {[x;y]n: count x;y: y mod n;if[y < 0; y: n + y];r: (n - y) _ x;y raze r,'x;} --> reserved command as variable, length error --> Grok 4 : (3/3) - correct --> rot:{[x;y] n:count x; if[0=n;:x]; k:y mod n; (k _ x),k # x } --> Kimi K2: (0/3) - incorrect --> [rot:{[x;y] (y rotate x)`long$'}] --> GPT-4o: (1/3) - incorrect, type error rotateString:{[x;y] len:count x; i:y mod len; (x i+til len-i),x 0 til i} x:"abc"; y:1; rotateString[x;y] // type error Q30) In kdb+/q - Outline what .Q.dpft does and each parameter it takes (medium - 5 points) --> Used to save down a partition table --> .Q.dpft[(directory);(partitioned date);(field);(table)] (e.g. .Q.dpft[`:db;2007.07.23;`sym;`trade]) * directory --> filepath were partition is/will be located * partition date --> end of day trading date to be saved down to the HDB * field --> usually parted attribute applied to sym column * table --> to save down --> 4 point - for each of the 4 parameters --> 1 point - explaining what the .Q namespace does Results: --> Sonnet Claude 4: (5/5) - `.Q.dpft` is a utility function in kdb+/q that saves tables to disk in a partitioned format. It's commonly used for creating date-partitioned historical databases. .Q.dpft[directory; partition; field; table] ## Parameters: ### 1. `directory` (symbol) - The root directory where the partitioned database is stored - Must be a symbol (e.g., `` `:hdb``, `` `:./database``) - This is where the partition subdirectories will be created ### 2. `partition` (date/int/month/etc.) - The partition value, typically a date - Creates a subdirectory named after this value - Common types: date (2023.01.15), int (20230115), month (2023.01m) ### 3. `field` (symbol) - The column name by which to sort the table - This column will receive the parted attribute (`` `p#``) - Should be a symbol column for optimal performance - Often this is `sym for symbol columns ### 4. `table` (symbol) - The name of the table to save - Must be a symbol representing the table name in memory --> Gemini 2.5 Pro (4/5) - .Q.dpft` is the standard, high-level utility function for saving an in-memory table to a partitioned database on disk (an HDB) .Q.dpft[d; p; f; t] d - directory p - The name of the column in the table `t` that will be used to partition the data (e.g. `date --> incorrect) f - A function to be applied to each table chunk (each partition's data) *before* it is saved. --> gives an example of apply grouped attribute which is the most memory intensive instead of parted t - The name of both the source table in memory and the target table on disk. --> Grok3: (4/5) - `.Q.dpft` is a utility function used to save a table to disk as a partitioned database. .Q.dpft[directory; partitionValue; tableName; tableData] --> tableName should be attribute applied a column name (e.g. `p#sym) other descriptions are correct --> Deepseek: (5/5) - The **`.Q.dpft`** function in kdb+/q is used to **save a keyed table to a partitioned database**, typically in a **date-partitioned** structure. ### Parameters: 1. **`directory`** (symbol atom) - Root directory path of the partitioned database (e.g., ``:./db`). - Must end with a slash (`/`). - Example: ``:./db/` 2. **`partition`** (date, month, year, or int) - Partition value (e.g., `2023.10.10` for daily partitioning). - Determines the subdirectory name under `directory`. - Must match the type of the partitioning column. 3. **`field`** (symbol atom) - Name of the **partitioning column** in the table (e.g., `` `date``). - This column must: - Exist in the table. - Be part of the **primary key**. - Be of type `date`, `month`, or `int` (depending on partitioning scheme). 4. **`table`** (symbol atom) - Name of the in-memory table to save (e.g., `` `trades``). - The table **must be keyed** (use `` `s#`` attribute for optimization). --> GPT-4o-mini: (0/5) - In kdb+/q, `.Q.dpft` is a function used to perform deferred plot functions. --> incorrect, parameters are nonsense here --> GPT-4.1 (0/5) - `.Q.dpft` is a system utility function in kdb+/q designed for **parsing a temporal datetime value from a variable format string**. The name stands for **d**ate/**p**arse/**f**ormat/**t**ext. .Q.dpft[type;format;text] --> GPT-3.5-Turbo (3/5) - mixed results, parameter order is wrong, mention up to six parameters which could be similar .Q functions .Q.dpft stands for "dynamic partitioned file table" and is a built-in function in kdb+/q that is used to partition a table and save it on disk. 1. `filePath` : This is a symbol representing the path on disk where the partitioned table will be saved. It can be an absolute or relative path. 2. `table` : This is the table that needs to be partitioned and saved on disk. 3. `partCol` : This is the column of the table that will be used for partitioning. The values in this column will determine how the table will be partitioned. 4. `partType` : This is a symbol representing the type of partitioning. It can be one of the following values: `date`, `month`, `year`, `minute`, `second`, `hh`,`md`, `ym`,`yd`,`vw`, `u`,`v`,`w`. 5. `partVal` : This is a list of partitioning values. These values determine how the table will be split into partitions based on the `partType` specified. 6. `param` : This is a dictionary containing additional parameters that can be used to specify compression, storage format, and other options for saving the partitioned table on disk. Overall, .Q.dpft is a powerful function in kdb+/q that allows users to efficiently partition and save large tables on disk, making it easier to manage and analyze large datasets. --> Grok 4 : (5/5) - .Q.dpft[directory; partition; sortColumn; tableName] saves tables in a partitioned database --> Kimi K2: (4/5) - .Q.dpft[dir;partition;p;f;table] is the standard, ready-made utility for writing a **fully-partitioned, splayed kdb+ table** to disk **with an in-segment enumerated symbol vector sorted on date, sym and time --> GPT-4o: (1/5) - .Q.dpft[hpub;table;sym;data] sends data to a tickerplant's subscribers for real-time updates Q31) What is protection evaluation in kdb+ and give me some examples (easy - 3 marks)? --> Used to throw custom detailed error, also known as error trapping --> Protection evaluation for single variable - @ apply at (e.g. @[sin;`a;{[error] "Incorrect Input = ", error}] ) --> Protection evaluation for multi variables - . apply (e.g. .[+;(`s;2);{[error] "Incorrect Input = ", error}]) --> 1 point - explaining what protection evaluation is --> 1 point - shows single use variable case using @ --> 1 point - shows multi use variable case using . Results: --> Sonnet Claude 4: (3/3) - Protection evaluation in kdb+ is a way to safely execute code and catch errors without causing the entire program to terminate. It's implemented using the `@` (monadic at) operator and `.` (dot) function, which allow you to trap errors and handle them gracefully. [`@[f;x;e]` - Protected Apply, `.[f;x;e]` - Protected Dot Apply] --> Gemini 2.5 Pro (3/3) - correct ### Summary Table | Feature | Syntax | Use Case | | ----------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | **Protect (Dot Apply)** | .[function; (arg1; arg2); fallback] | Safely execute a function, passing arguments as a list. | | **Protect (Func Apply)**| @[function; arg1; arg2; fallback] | Safely execute a function, passing arguments individually. Often faster. | --> Grok3: (1/3) - protection evaluation is a concept related to how the system handles errors or exceptions during query execution or function evaluation. No mention of apply or dot syntax --> Deepseek: (0/3) - incorrect, IPC related info Protection Evaluation in kdb+** refers to the built-in security mechanism that intercepts and validates operations (like queries or table accesses) through customizable callbacks --> --> GPT-4o-mini: (0/3) - incorrect, Tickerplant related info In kdb+, protection evaluation is a mechanism that allows you to control the visibility and accessibility of data within a database, especially when dealing with sensitive or critical information --> --> GPT-4.1 (0/3) - incorrect concept *Protection evaluation** in **kdb+** refers to a mechanism that controls the level of **privilege** or **capabilities** code has when it is being evaluated (i.e., executed). --> GPT-3.5-Turbo (0/3) - incorrect, no mention of key info Protection evaluation in kdb+ is a feature that allows users to restrict access to both data and functions within the kdb+ environment. --> Grok 4 : (3/3) - correct In kdb+ (q), **protected evaluation** is a mechanism to safely evaluate (or "apply") a function or expression while handling potential errors gracefully. It prevents your code from crashing due to runtime errors (e.g., type mismatches, domain errors, or signals like `'type`, `'rank`, or `'domain`) by providing a fallback value or handler. This is primarily achieved using two overloads of the apply operators: - **`@`** (at): Used for **unary** (single-argument) function application with protection. - **`.`** (dot): Used for **general** (multi-argument) function application with protection. `@[func; arg; handler]` or `.[func; args; handler] @[neg; (1; "a"); 0N] / Fails (type error: can't negate a string), returns 0N (integer null) 0N .[til; (1b); "Invalid input"] / Fails (til expects an integer, not boolean), returns custom string "Invalid input" --> Kimi K2: (1.5/3) - incorrect, doesn't show multi variable case, wrong about single use case kdb+ uses *protected evaluation* to ship the run-time risk of a message to an **error trap** rather than crashing the session. @[{x%y}; (1;0); `err] --> GPT-4o: (0/3) - incorrect In kdb+, **protection evaluation** is a mechanism to control the scope and execution of code within a namespace (`.z.p` evaluation). This feature is designed to provide a safer and more controlled runtime environment, typically used for isolating user-defined functions or dynamic code execution from the default namespace. Essentially, with protection evaluation, code can be evaluated in a custom namespace, where variables and functions defined in the base namespace (`.`) are not directly accessible. This mechanism can help prevent accidental modifications or access to sensitive resources and create controlled behavior for specific parts of an application. ### Example of Protection Evaluation #### Basic Example Here's an example that demonstrates how protection evaluation works: ```q // Define a namespace `.protected` with some scoped variables .protected.a: 42 .protected.b: "hello" Q32) What are the conditional statements in kdb+ and give an example? (easy - 3 marks) --> if statement - if true than do all the following commands, does not return anything (e.g. if[1b; 2+2] ) --> Atomic Conditional Evaluation - single statement eval (e.g. $[x>5; `yes; `no]), can have multiple nested atomic cond statements --> Vector Conditional Evaluation - multiple statement eval (e.g. ?[1 2= 1 3; `yes; `no] --> ?[10b; `yes; `no]) --> 1 point - if statement --> 1 point - atomic cond eval --> 1 point - vector cond eval Results: --> Sonnet Claude 4: (3/3) - correct [if, atomic cond eval, multiple atomic cond eval, vector cond eval] --> Gemini 2.5 Pro: (3/3) - correct [if, atomic cond eval, multiple atomic cond eval, vector cond eval] --> Grok3: (2/3) - missing vector cond eval, mentions do statement which is more related to overloaded iteration --> Deepseek: (3/3) - correct [if, atomic cond eval, multiple atomic cond eval, vector cond eval] --> GPT-4o-mini: (1/3) - mention of switch statement (doesn't exist) and if statement --> GPT-4.1 (2/3) - missng vector conditional statement --> GPT-3.5-Turbo (1/3) - only shows if statement but it works --> Grok 4 : (2/3) - missing vector cond eval if[condition; expression] Conditional -->$[condition; true_expression; false_expression] Multi-Way Conditional --> $[cond1; expr1; cond2; expr2; ... ; default_expr] --> Kimi K2: (3/3) - correct `$[cond; exprT; exprF]` --> Classic ternary – exactly one branch evaluated. ?[cond; exprT; exprF]` --> Vector (or scalar) form – *both* branches evaluated then selected; cheap when data are large. if[cond; expr]` --> Executes `expr` only if `cond`; always returns **generic null** (`::`). | --> GPT-4o: (2/3) - missing atomic cond eval if[condition;expression] ?[condition;true_expression; false_expression] Q33) What are the methods of casting in kdb+/q and give an example of each? (easy - 4 marks) --> Symbol casting (e.g. `float$4 --> 4f) --> String casting (e.g. "F"$"4" --> 4f), a note should be made about casting from a string datatype --> Short casting (e.g. 9h$4 --> 4f) --> 1 point each for the three casting methods --> 1 point for how to cast from a string as the other casting methods will not give the desired results Results: --> Sonnet Claude 4: (4/4) - correct [symbol, short, string casting with examples] --> Gemini 2.5 Pro (2/4) - mixed results [symbol, string, using value to cast from string to other datatypes] --> missing short casting, some symbol casting examples are incorrect (e.g. `f$5 --> 5f) --> Grok3: (2/4) - mixed results [symbol, string, cast function] --> Deepseek: (1/4) - mixed results [set of string casting examples] --> GPT-4o-mini: (2/4) - mixed results [symbol, string casting] --> GPT-4.1 (1/4) - mixed results [symbol, implict casting] --> GPT-3.5-Turbo (0/4) - incorrect [cast function, casting using literals (e.g. 3.14$int), casting using enlist function] --> Grok 4 : (3.75/4) - minor syntax issues with symbol casting casting with type character --> "f"$42 --> 42f casting with type number --> -11h$("hello";"world") --> `hello`world casting with type name --> timestamp$2023.01.01 --> 2023.01.01D00:00:00.000000000 implicit casting casting using commands (e.g. string) --> Kimi K2: (0/4) - incorrect unary casting --> `i$42.7 --> 42i binary casting --> $[`int;98.6;::] --> 98i dollar-casting --> 42.7`int --> 42i --> GPT-4o: (1/4) - incorrect casting using `$ --> `int$"42" --> 42 // Cast string to integer casting lists and vectors implicit casting Q34) What is the difference between an explicit and implicit function in kdb+/q and give an example of each? (easy - 2 marks) --> Explicit functions - where parameters taken are clearly defined (e.g. f:{[len;width] len*width}), 8 parameters max otherwise rank error --> Implicit functions - where parameters taken are NOT defined (e.g. f:{x*y+z} ), 3 parameters max --> 1 point to explain what each is Results: --> Sonnet Claude 4: (1.5/2) - limit is 8 but claims no inherent limit ## Key Differences | Aspect | Explicit Functions | Implicit Functions | |-------------------------------------------|------------------------------------------------------------------------|------------------------------------------------------| | **Parameter Declaration** | Must declare parameters in `[]` | Use predefined `x`, `y`, `z` | | **Parameter Names** | Custom names | Fixed names (`x`, `y`, `z`) | | **Maximum Parameters** | No inherent limit | Limited to 3 (`x`, `y`, `z`) | | **Readability** | More descriptive with meaningful names | More concise but less descriptive | | **Use Case** | Better for complex functions | Good for simple, quick functions | --> Gemini 2.5 Pro (2/2) - correct Feature | Explicit Function | Implicit Function (Lambda) --------------------------------+--------------------------------------------------+--------------------------------------------------- Argument Definition | Declared in square brackets [] | Not declared; implicit Argument Names | User-defined (e.g., price, size) | x, y, z Readability | High, especially for complex logic | Lower, requires knowing the x, y, z convention Local Variables | Supported (e.g., {[a;b;loc]...}) | Not supported Max Arguments | 8 | 3 Syntax Example | {[width;height] width*height} | {x*y} Common Use Case | Reusable functions, complex business logic | Quick inline ops, adverbs (' / \), select/update --> Grok3: (2/2) - correct ### **Key Differences** | **Aspect** | **Explicit Function** | **Implicit Function** | |-------------------------------|---------------------------------------------------------------------------------|--------------------------------------------| | **Definition** | Defined using curly braces `{}` with parameters. | Not explicitly defined; implied by context or operator. | | **Reusability** | Named and reusable across code. | Often inline and specific to the operation. | | **Syntax** | Clear and structured (e.g., `{x + y}`). | Shorthand or derived (e.g., `+':`). | | **Use Case** | For complex logic or reusable code. | For concise, one-off operations. | --> Deepseek: (2/2) - correct **Key Differences**: | Feature | Explicit Function | Implicit Function | |---------------------------|--------------------------------------------------|----------------------------------------------------------------| | **Definition** | Braces with arguments: `{...}` | Projection (`f[;c]`) or adverb (`g each`) | | **Arguments** | Declared (e.g., `[a;b]`) or `x`,`y` | Inferred from partial application | | **Use Case** | Complex multi-line logic | Concise derived operations | --> GPT-4o-mini: (2/2) - correct **Explicit Function**: Named, defined using the `func:` syntax, can have multiple lines, useful for complex operations. - **Implicit Function**: Anonymous, often single-expression, used for quick operations and can be combined with operators like `each`. --> GPT-4.1 (2/2) - correct | Style | Definition Syntax | Example | Notes | |------------|------------------------------------------------|-----------------------------------|--------------------------------------------------------| | Implicit | `{x + y}` | `{x * 2}` | Uses positional parameters x, y, z | | Explicit | `f[x;y]: x + y` | `double[x]: x * 2` | You name parameters on left of colon | --> GPT-3.5-Turbo (2/2) - correct examples In kdb+/q, an explicit function is defined using the `function:{}` notation and requires specifying the arguments and body of the function. On the other hand, an implicit function is defined using the `{}` notation without specifying the arguments or body. --> Grok 4 : (2/2) - correct **Implicit Functions**: - Do **not** explicitly declare parameter names in square brackets `[]`. - Rely on default implicit variable names: `x` (first argument), `y` (second argument), and `z` (third argument). - Limited to **at most 3 arguments** (since only `x`, `y`, and `z` are available implicitly). For more than 3 arguments, you must use an explicit function or other workarounds (e.g., passing a list or dictionary). - Simpler and more concise for quick, short functions with few arguments. - Cannot assign default values to parameters. - Often used for ad-hoc or functional programming styles (e.g., with operators like `/` or `\` for iteration). addImplicit:{x + y} - **Explicit Functions**: - **Explicitly declare** parameter names in square brackets `[]` right after the opening `{` (e.g., `{[param1;param2] ... }`). - Can use any valid variable names for parameters (not limited to `x`, `y`, `z`). - Support **up to 8 arguments** (the q language limit for function arity). - Allow advanced features like **default values** for parameters (e.g., `{[x;y;x:10] ... }`). - More readable and self-documenting, especially for complex functions or those with many parameters. - Required if you need more than 3 arguments or want to avoid relying on implicit `x`/`y`/`z`. avgExplicit:{[num1;num2;num3] (num1 + num2 + num3) % 3} --> Kimi K2: (1.5/2) - confusing projections with implicit functions - **Explicit (lambda-form) function** You supply a visible parameter list and body. The parameters are listed **between the first pair of square brackets**, so their arity is statically known. Definition syntax: `{[…] …}` - **Implicit (project-form “projection”) function** You do **not** mention parameters at all; instead you take an already existing function (a q primitive or a lambda you wrote earlier) and *partially apply* some of its arguments with concrete values. The runtime returns another function whose only unknown arguments **remain implicit**—they are whatever still has to be supplied when the resulting function is finally called. No `{…}` construct is used; you simply evaluate a projection expression. --> GPT-4o: (2/2) - correct ### 1. Explicit Functions An explicit function is defined using the `funcname:{[parameters] ... }` syntax. Explicit functions explicitly list their parameters and utilize a structured form that clearly defines the function's arguments. These functions are more verbose but provide greater flexibility and clarity, especially for functions requiring multiple arguments or complex logic. #### Example of Explicit Function ```q // Define explicit function to calculate the square of a number square:{[x] x*x} // Call the function square 4 // Output: 16 ``` **Explanation:** - `[x]` specifies the parameter name `x`. - The function body `x*x` performs the operation using the argument `x`. ### 2. Implicit Functions An implicit function is defined without explicitly specifying parameter names. It is a concise way of defining a function, relying on the fact that parameters are referred to as `x`, `y`, and `z` (the implicit variables). This style is compact but trades off clarity. It is typically used for simple functions with one or two arguments. #### Example of Implicit Function ```q // Define implicit function to calculate the square of a number square:{x*x} // Call the function square 4 // Output: 16 ``` Q35) In kdb+/q - What is the maximum amount of variables an explicit function can take? How can I get around this limitation? (easy - 2 marks) --> 8 parameters is the max or rank error occurs --> We get around this by passing parameter in as a dictionary with the keys as the variable symbol names and values as the variable data --> 1 point - correct max amount of variables --> 1 point - method of getting around this (storing variables in lists, dictionaries, tables) Results: --> Sonnet Claude 4: (2/2) - In kdb+/q, an explicit function can take a **maximum of 8 parameters**. Workarounds [dictionary, lists, nested functions] --> Gemini 2.5 Pro (2/2) - In kdb+/q, an **explicit function** (one defined with square brackets `[...]` for its arguments) can take a maximum of **8** arguments. If you try to define a function with 9 or more arguments, you will get an `'arity` error --> incorrect, this error doesn't exist To get around this limitation, the two primary methods are using a **list** or a **dictionary**. --> Grok3: (2/2) - limited to a **maximum of 8 arguments**. Workarounds [Pass Arguments as a Single List or Dictionary] --> Deepseek: (2/2) - In kdb+/q, **explicit functions can take a maximum of 8 parameters**. Workarounds include using a dictionary or list argument. --> GPT-4o-mini: (1/2) - In kdb+/q, an explicit function can take up to 1024 arguments. Workarounds [use dictioanries, lists, tables] --> GPT-4.1 (2/2) - In kdb+/q, **an explicit function can take a maximum of 8 arguments**. Workarounds include using a dictionary or list argument. --> GPT-3.5-Turbo (2/2) - In kdb+/q, the maximum number of arguments that an explicit function can take is 8. If you need to pass more than 8 arguments to a function, you can use dictionaries or lists to group the arguments together. --> Grok 4 : (2/2) - correct [implict func = 3, explicit func = 8, pass arguments as list or dictionary] --> Kimi K2: (2/2) - correct [explicit func = 8, pass arguments in a list or dictionary] --> GPT-4o: (2/2) - correct [explicit func = 8, pass arguments in a list or dictionary] Q36) What are the 3 commands in kdb+/q that can remove leading and/or trailing white/empty spaces from strings (easy - 3 points) --> ltrim - monadic function that removes leading or left whitespace from strings --> rtrim - monadic function that removes trailing or right whitespaces from strings --> trim - removes both leading and trailing whitespaces from strings --> 1 point for each command, explaining what each command does Results: --> Sonnet Claude 4: (3/3) - [ltrim, rtrim, trim] --> Gemini 2.5 Pro (3/3) - [ltrim, rtrim, trim] --> Grok3: (3/3) - [ltrim, rtrim, trim] --> Deepseek: (3/3) - [ltrim, rtrim, trim] --> GPT-4o-mini: (1/3) - [trim, using each on multiple strings] --> GPT-4.1 (3/3) - [ltrim, rtrim, trim] --> GPT-3.5-Turbo (1/3) -[trim, trimr (doesn't exist), using sv (incorrect example)] --> Grok 4 : (3/3) - correct [trim, ltrim, rtrim] --> Kimi K2: (3/3) - correct [trim, ltrim, rtrim] --> GPT-4o: (1/3) - incorrect [ssr, trim, sv] Q37) In kdb+/q, what command lets me replace specific letters in a string and give me an example (easy - 2 points) --> string, search and replace command (e.g. ssr["hello world";"o";"s"] --> "hells wsrld") --> 1 point - giving correct command --> 1 point - giving a working example, explaining parameters Results: --> Sonnet Claude 4: (2/2) - correct (ssr[string; pattern; replacement]) --> Gemini 2.5 Pro (2/2) - correct (ssr[sourceString; searchString; replacementString]) --> Grok3: (2/2) - correct (ssr[string; search; replace]) --> Deepseek: (1.5/2) - explains ssr right but also mentions a non-existent reserved command called tr that does a similar thing --> GPT-4o-mini: (0/2) - non-existent reserved command, str replace which takes 3 parameters --> GPT-4.1 (2/2) - correct (ssr[string; target; replacement]) --> GPT-3.5-Turbo (2/2) - correct (ssr["hello world"; "o"; "0"] --> "hell0 w0rld") --> Grok 4 : (2/2) - correct ssr["banana"; "a"; "o"] --> "bonono" --> Kimi K2: (2/2) - correct ssr/[;"e";"*"] ssr[;"o";"*"] "Hello, kdb+ world!" --> "*H*ll*, kdb+ w*rld!" --> GPT-4o: (2/2) - correct ssr["banana"; "a"; "x"] --> "bxnxnx" Q38) In kdb+/q, what is the difference between a simple list and general list? Give me an example. (easy - 2 points) --> Simple list - each value in the list is the same datatype with the list type being positive (e.g. l: 3 4 5 6) --> General list - multi-dimensional simple list and lists with at least 2 different datatypes. type = 0h (e.g. l: (4;"hello";`s; 8e)) --> 1 point - explaining the key differences --> 1 point - showing examples for each Results: --> Sonnet Claude 4: (2/2) - correct, examples work well ## Simple List - **Homogeneous**: All elements are of the same type - **Efficient storage**: Uses contiguous memory layout - **Better performance**: Optimized for vectorized operations - **Type consistency**: Has a single atomic type ## General List - **Heterogeneous**: Can contain elements of different types - **Mixed storage**: Uses pointers to different memory locations - **Slower operations**: Less optimized due to type diversity - **Mixed types**: Contains multiple data types --> Gemini 2.5 Pro (2/2) - correct, examples work * A **simple list** is a **homogeneous** collection, meaning all its elements are of the **same data type**. * A **general list** is a **heterogeneous** collection, meaning its elements can be of **different data types**. --> Grok3: (2/2) - correct, examples work ### **Key Differences** | **Aspect** | **Simple List** | **General List** | |------------------------------------|-------------------------------------------------------------|--------------------------------------------------------------| | **Type Homogeneity** | All elements are of the same type. | Elements can be of different types. | | **Type Code** | Specific type code (e.g., `7h` for long). | Always `0h`. | | **Efficiency** | More efficient (faster, less memory). | Less efficient (more memory overhead). | | **Use Case** | Used for uniform data (e.g., time series).| Used for mixed data or nested lists. | --> Deepseek: (2/2) - correct, examples work ### Key Distinctions: | Feature | Simple List | General List | |------------------------------|-------------------------------------------------|------------------------------------------------| | **Element Type** | All elements same atomic type | Mixed types or nested lists | | **Structure** | Flat (no nesting) | Hierarchical (may have nesting)| | **Type Code** | Specific (e.g., `7h`, `10h`) | Always `0h` | | **Creation** | `[...]`, `"abc"`, or `1 2 3` | `(item1; item2; ...)` | --> GPT-4o-mini: (2/2) - correct, examples work A **simple list** (e.g., `1 2 3`) is homogeneous (all elements of the same type). A **general list** (e.g., `(1; "two"; `symbolType; (4 5 6))`) is heterogeneous and can contain mixed types and nested lists. --> GPT-4.1 (2/2) - correct, examples work Use simple lists when you have uniform data. Use general lists when you want to hold varied types in one list. --> GPT-3.5-Turbo (2/2) - a simple list is a one-dimensional list containing elements of the same data type, while a general list is a nested list containing elements of different data types. [simpleList: (10 20 30 40 50) generalList: (("apple"; 5); (10; "banana"))] --> Grok 4 : (2/2) - correct [simple lists same type, mixed list different types] simpleList: 1 2 3 4 5 generalList: (1; 2.5; `abc; 3 4 5) --> Kimi K2: (2/2) - correct A simple list contains atoms all of the same type; every element has identical type/length, so the whole structure can be stored contiguously in memory and has a uniform type code. A general list can hold atoms of mixed type or even nested/other lists; it is therefore stored as (a vector of) pointers and has the generic‐type code 0h. Examples: ``` q)sl: 1 4 9 16 / simple list → 7h (vector of longs) q)gl: (1; 4.2; "abc") / general list → 0h (mixed types) q)type sl 7h q)type gl 0h --> GPT-4o: (2/2) - correct In kdb+/q, the primary distinction between a **simple list** and a **general list** lies in the **type homogeneity** of the elements in the list. 1. **Simple List:** - All elements in the list are of the same type (homogeneous). - Simple lists are more memory-efficient and perform better because they are stored contiguously in memory. **Example:** ```q q) simpleList: 1 2 3 4 5 q) type simpleList 7h / This means it is a list of integers ``` 2. **General List:** - Contains elements of **different types** (heterogeneous). - Less memory-efficient due to the need to store additional metadata for each element. - General lists are denoted with parentheses `()` when defined explicitly. **Example:** ```q q) generalList: (1; "hello"; 3.14) q) type generalList 0h / This indicates it is a general list ``` **Key Differences:** - A **simple list** (like `1 2 3 4`) is type-specific (e.g., all integers, floats, or strings), while a **general list** (like `(1; "hello"; 3.14)`) can mix types. - Operations on simple lists are faster since they are stored as arrays in memory, compared to general lists which involve additional overhead for managing mixed types. You can test the type of a list by using the `type` function. Simple lists have a positive type code (e.g., `7h` for integers, `9h` for floats, etc.), whereas general lists always have a type code of `0h`. Q39) In kdb+/q, what are some differences between using the take (#) command and using the sublist command on a list? Show me an example of the differences. (easy - 2 point) --> take (#) starts from the first/last n elements while sublist can specify a sub range of elements --> take (#) can generate a list longer than the list itself if asked while sublist cannot (e.g. 3#1 2 --> 1 2 1 | 3 sublist 1 2 --> 1 2) --> take (#) can take negative values, which starts from the end while sublist cannot --> take (#) can have two parameters while sublist can take 2 or 3 parameters --> 1 point - explaining the difference --> 1 point - showing an example Results: --> Sonnet Claude 4: (1.5/2) - mostly correct [some incorrect info mixed in, e.g. l: 1 2 3 --> claiming 10#l is the same output as 10 sublist l] **Use `#` (take) when:** - You need elements from the beginning or end of a list - You want simpler, more readable syntax - You're doing basic list truncation **Use `sublist` when:** - You need to extract from the middle of a list - You need more precise control over start position - You're implementing sliding windows or pagination - You need to take elements preceding a position (negative count) --> Gemini 2.5 Pro (0.5/2) - [data copy (take) vs data view (sublist) -->nonsense claims, null values added on for take (#) out of bounds cases, negative indexing for take] --> Grok3: (1.5/2) - mostly correct [syntax, negative value for take, takes cycles through the list while sublist stops if it reaches end of the list] syntax uses round brackets (e.g. sublist(7,l)) --> Deepseek: (2/2) - correct [syntax, negative value for take, takes cycles through the list while sublist stops if it reaches end of the list] correct syntax (e.g. (1;2) sublist L) --> GPT-4o-mini: (0/2) - incorrect [syntax shows is wrong] --> GPT-4.1 (1.5/2) - mostly correct [some wrong syntax and claims] **Summary:** - `#` can be used to repeat elements if more are requested than exist. - `sublist` never repeats, and you control the window of data using the starting position and length. - Use `#` if you want "n elements" (from start/end, possibly repeated), - Use `sublist` for "a window of length n from position p" (never wraps/cycles). --> GPT-3.5-Turbo (0/2) - incorrect claims [The sublist command will return an error if the requested index is out of bounds, while the take command will return as many elements as possible within the bounds of the list.] --> Grok 4 : (0.5/2) - incorrect [claims sublist command doesn't exist in kdb+/q, take examples are correct] --> Kimi K2: (1/2) - no examples of using the sublist command * `#` falls back to taking the items cyclically when the requested length overshoots the list; `sublist` simply returns what is available. * `#` works naturally with matrices and negative counts; `sublist` does not. --> GPT-4o: (0.5/2) - incorrect, refers to indexing and not the sublist command Q40) In kdb+ tickerplant architecture, how do I change the tick process from batch mode to real time mode? (medium - 2 points) --> when starting tick process - q tick.q SRT DRC [-p 5010][-t 1000][-o offset] , the -t parameter (0 = default mode, any other time = batch mode) --> could not include -t parameter as well for real time mode --> 1 point - outlining start up syntax for tick process --> 1 point - changing of the t parameter controls if tick process runs in batch mode or real time mode Results: --> Sonnet Claude 4: (2/2) - [q tick.q sym .-p 5010 -t 0] --> correct --> Gemini 2.5 Pro (0.5/2) - mentions modifications to .u.upd or disabling .z.ts timer --> Grok3: (0.5/2) - series of steps involving disabling of batch specific logic --> Deepseek: (1/2) - [q tick.q -p -t 100] --> incorrect, claims t parameter is negative for batch mode & positive for real-time --> GPT-4o-mini: (0/2) - more advice on methods of possibility doing it which are iffy --> GPT-4.1 (1/2) - [q tick.q sym -p 5010 :5011 0] --> syntax is somewhat incorrect --> GPT-3.5-Turbo (0/2) - mentions the possibility of changing a parameter in the tickerplant configuration file --> Grok 4 : (2/2) - correct [q tick.q sym /path/to/log/dir -p 5010 -t 0] --> Kimi K2: (1/2) - incorrect [q tick.q sym d ] --> partially incorrect --> GPT-4o: (0/2) - incorrect [finish replay process, check replay completion] Q41) In kdb+/q, how do I force a garbage collection? (easy - 1 point) --> .Q.gc[] or system "g -1" --> 1 point - outlining garbage collection method and some detail on it Results: --> Sonnet Claude 4: (1/1) - .Q.gc[] --> Gemini 2.5 Pro (1/1) - .Q.gc[] --> Grok3: (1/1) - .Q.gc[] --> Deepseek: (1/1) - .Q.gc[] --> GPT-4o-mini: (0/1) - gc[] --> GPT-4.1 (0.5/1) - system "g" --> GPT-3.5-Turbo (1/1) - .Q.gc[] --> Grok 4 : (1/1) - correct [.Q.gc[]] --> Kimi K2: (1/1) - correct [.Q.gc[]] --> GPT-4o: (1/1) - correct [.Q.gc[]] Q42) In kdb+/q, there are no for loops like other programming language. What do they use instead? (easy - 1 point) --> Usage of iterators/adverbs (atomic, mapping, accumulator, overloaded iteration) --> 1 point - outlining iterators/adverbs as the replacement to for loops Results: --> Sonnet Claude 4: (1/1) - vector operation, iterators (each, each-left, each-right, scan [\], over [/]) --> Gemini 2.5 Pro (1/1) - vector operation, iterators, do/while loops (discourged) --> Grok3: (1/1) - vector operation, iterators (each, each-left, each-right, scan [\], over [/]), do/while loops --> Deepseek: (1/1) - vector operation, iterators (each, each-left, each-right, scan [\], over [/]), do/while loops --> GPT-4o-mini: (0/1) - map function, where clause, fold (/), scan (\) --> GPT-4.1 (1/1) - vector operation, iterators (each, each-left, each-right, scan [\], over [/]), do/while loops --> GPT-3.5-Turbo (1/1) - developers typically use function application and iteration to achieve similar functionalities. --> Grok 4 : (1/1) - correct [vectorized operators and/or adverbs (iterators)- each, over, scan, peach] --> Kimi K2: (1/1) - correct [iterators/adverbs (each, over, scan) and vector operations] --> GPT-4o: (1/1) - correct [vectorized operations, each, each-right, each-left] Q43) Using kdb+/q, how do I generate a random list with each value in that list being unique? (easy - 2 point) --> Using random list generation with a negative value (e.g. -10?20) --> 1 point - outlining random list generation using ? operator --> 1 point - using a negative value to make the random list unique Results: --> Sonnet Claude 4: (2/2) - random listing generation with negative value (e.g. -5?til 10) --> Gemini 2.5 Pro (1/2) - random list generation, no mention of negative value --> Grok3: (1/2) - random list generation, no mention of negative value --> Deepseek: (1/2) - random list generation, no mention of negative value --> GPT-4o-mini: (0/2) - no list generation or negative value (e.g. distinct rand[100] cut 10 ) --> GPT-4.1 (0/2) - mention of a pre-defined sample function (e.g. sample[10;5] --> 2 7 4 1 5) --> GPT-3.5-Turbo (1/2) - asc 10?10*n --> asc only sorts list in ascending order --> Grok 4 : (1/2) - incorrect, missing negative value in all examples [10?(til 1000000000)] --> Kimi K2: (0/2) - incorrect uniqRand:{[n;r] distinct r[;0] n?r}[;0N] 5 uniqRand 100 / 5 unique ints from 0…99 36 7 91 52 4 --> GPT-4o: (1/2) - incorrect, missing negative value in all examples [n?range] Q44) Using kdb+/q, how can I convert a singleton list to an atom (easy - 1 point) --> Can use the first or last command (e.g. l:,1 --> l: first l --> l = 1 now) --> 1 point - using first or last command Results: --> Sonnet Claude 4: (1/1) - first command, index notation, --> Gemini 2.5 Pro (1/1) - first command, index method, using raze --> Grok3: (1/1) - first command, index method --> Deepseek: (1/1) - first command, index method, using raze --> GPT-4o-mini: (1/1) - first command, index method --> GPT-4.1 (1/1) - first command, index method, using raze --> GPT-3.5-Turbo (0.5/1) - list: (42); atom: list 0 --> not a list, can work if so (index method) --> Grok 4 : (1/1) - correct [first, indexing, raze] --> Kimi K2: (0.5/1) - incorrect [doesn't exactly say use first/last command but shows an example for a two item list] --> GPT-4o: (1/1) - correct [use first command] Q45) Using kdb+/q, how can I convert an atom into a singleton list (easy - 1 point) --> Use the enlist command (e.g. l: 1 --> l: enlist l --> l = ,1 now) --> 1 point - using enlist command Results: --> Sonnet Claude 4: (1/1) - enlist 5 --> Gemini 2.5 Pro (1/1) - enlist `a --> Grok3: (1/1) - using enlist --> Deepseek: (1/1) - enlist --> GPT-4o-mini: (1/1) - enlist, does mention other incorrect methods of doing so --> GPT-4.1 (1/1) - correct --> GPT-3.5-Turbo (1/1) - using enlist (e.g. enlist 42) --> Grok 4 : (1/1) - correct [enlist] --> Kimi K2: (1/1) - correct [enlist] --> GPT-4o: (1/1) - correct [enlist] Q46) Using kdb+/q, which command can I use to convert a symbol into a file path? (easy - 1 point) --> use the hsym command (e.g. hsym `summary --> `:summary) --> 1 point - hsym command Results: --> Sonnet Claude 4: (1/1) - correct --> hsym command (e.g. hsym `symbol --> `:symbol) --> Gemini 2.5 Pro (0/1) - incorrect --> hopen command --> Grok3: (0/1) - incorrect --> string command --> Deepseek: (1/1) - correct --> hsym command --> GPT-4o-mini: (0/1) - incorrect --> string command --> GPT-4.1 (0/1) - incorrect --> string command --> GPT-3.5-Turbo (0/1) - incorrect --> casting using `$ --> Grok 4 : (1/1) - correct --> hsym --> Kimi K2: (0/1) - incorrect --> casting using `$ --> GPT-4o: (0/1) - incorrect --> string command Q47) Using kdb+/q, how can I split up a string based on a value in the string? Give me an example. (easy - 2 points) --> use the vs command (e.g. vs["|"; "hello|fun|sun"] --> ("hello";"fun";"sun") ) --> 1 point - showing vs command --> 1 point - giving a working example Results: --> Sonnet Claude 4: (2/2) - "," vs "apple,banana,cherry" --> correct --> Gemini 2.5 Pro (2/2) - "," vs "AAPL,GOOG,MSFT,AMZN" --> correct --> Grok3: (1/2) - "apple,banana,orange,grape" vs "," --> incorrect, parameters need to be swapped --> Deepseek: (2/2) - "," vs "apple,banana,cherry" --> correct --> GPT-4o-mini: (0/2) - uses ss command but calls it string split --> incorrect --> GPT-4.1 (0.5/2) - "," sv "apples,oranges,bananas,kiwi" --> mentions vs and sv can both split a string apart --> GPT-3.5-Turbo (1/2) - vs["Hello,World,How,Are,You";","] --> incorrect, parameters need to be swapped --> Grok 4 : (2/2) - ["|" vs "apple|banana|cherry" --> ("apple";"banana";"cherry")] --> correct --> Kimi K2: (2/2) - " : " vs "INFO : 2023-11-30 : login : user=admin" --> ("INFO"; "2023-11-30"; "login"; "user=admin")] --> correct --> GPT-4o: (0/2) - use ss function, which is string search --> incorrect Q48) Using kdb+/q - what command can I use to join a set of strings? Give me an example. (easy - 2 points) --> use the sv command (e.g. sv["|"; ("hello";"fun";"sun")] --> ("hello|fun|sun") ) --> 1 point - showing sv command --> 1 point - giving a working example Results: --> Sonnet Claude 4: (2/2) - " " sv ("hello";"world";"from";"kdb") --> correct --> Gemini 2.5 Pro (2/2) - " " sv ("Hello"; "kdb+"; "World") --> correct --> Grok3: (2/2) - "," sv ("apple";"banana";"orange") --> correct --> Deepseek: (2/2) - "," sv ("Hello"; "world"; "from"; "kdb+/q") --> correct --> GPT-4o-mini: (2/2) - " " sv ("apple"; "banana"; "cherry") --> correct --> GPT-4.1 (2/2) - " " sv ("apple"; "banana"; "cherry") --> correct --> GPT-3.5-Turbo (2/2) - ", " sv ("Hello"; "world"; "!") --> correct --> Grok 4 : (2/2) - "," sv ("hello"; "world"; "from"; "q") --> "hello,world,from,q" --> correct --> Kimi K2: (1.5/2) - ", "/ sv ("red"; "green"; "blue") --> "red, green, blue" --> incorrect, no point in forward slash --> GPT-4o: (2/2) - " " sv ("Hello"; "world"; "kdb+") --> "Hello world kdb+" --> correct Q49) In kdb+, what is the name of the data structure of the key and value of a keyed table? (easy - 1 point) --> A keyed table is made up of a key!value pairing of unkeyed tables --> Of course, the key value pairing is of a dictionary --> 1 point - unkeyed tables for the key and value Results: --> Sonnet Claude 4: (1/1) - A keyed table is internally represented as a **dictionary** where: The **key** is a table containing the key columns. The **value** is a table containing the non-key (value) columns. --> Gemini 2.5 Pro (1/1) - Key!Value pairing --> Table --> Grok3: (1/1) - The key of a keyed table is a **table**. The value of a keyed table is also a **table** --> Deepseek: (1/1) - Key = Table (98h), Value = Table (98h) --> GPT-4o-mini: (0/1) - The keys are typically stored in a list, and the values can be stored in a separate column or also in a list, depending on the structure of the table. --> GPT-4.1 (1/1) - **key** is a *table*. **value** is another *table* --> GPT-3.5-Turbo (0/1) - The data structure of the key and value of a keyed table in kdb+ is called a dictionary. --> Grok 4 : (0.5/1) - incorrect [brief response --> table] --> Kimi K2: (0.5/1) - incorrect [the **key** of a keyed table is a **dictionary**, and the **value** is a **table**.] --> GPT-4o: (1/1) - correct [The keys are tables (often unique column combinations).] - The values are tables associated with those keys. Q50) In kdb+/q, what is a projection and what is its type? (easy - 2 point) --> A function with less parameters inputted than required (e.g. {x+y}[1] ) --> Trying it out - type {x+y}[1] --> 104h --> 1 point - stating the type of a projection is 104h --> 1 point - defining a projection Results: --> Sonnet Claude 4: (2/2) - A projection is created when you provide fewer arguments to a function than it expects. The type of a projection is **104h** (positive atom) --> Gemini 2.5 Pro (1/2) - A **projection** is a new function created by "fixing" or "pre-filling" one or more arguments of an existing function. type = 102h --> Grok3: (1/2) - A **projection** is a partially applied function, where one or more arguments of a function are fixed. type of `100h` --> Deepseek: (2/2) - a **projection** is a partially applied function where you fix one or more arguments of a function. Type = 104h --> GPT-4o-mini: (0/2) - a projection is a fundamental operation that creates a new table by selecting specific columns from an existing table while optionally applying transformations to those columns. Type = 0h --> GPT-4.1 (1/2) - A **projection** in kdb+/q is a *partially applied function*. It is what you get when you call a function but provide **fewer arguments than it expects**. Type = 100 h --> GPT-3.5-Turbo (1/2) - a projection is a functional concept that involves creating a new function based on an existing function by fixing (or partially applying) some of its arguments. This allows for more flexible and modular programming. The type of a projection depends on the argument(s) that are fixed when creating the new function. --> Grok 4 : (2/2) - a **projection** is a functional programming concept derived from partial application. It occurs when you invoke a function (or operator) with fewer arguments than its full arity (valence, i.e., the number of parameters it expects). The result is a new, partially applied function that "remembers" the provided arguments and awaits the remaining ones. Type = 104h --> Kimi K2: (1/2) - *a projection is a sub-function obtained by fixing one or more leading positional (left) arguments of a function, resulting in a new function that expects its remaining arguments later**. Type = 0h --> GPT-4o: (1/2) - a **projection** is a partially applied function where some arguments of the original function are fixed, but others are left unspecified. It essentially creates a new function that "remembers" the fixed arguments and waits for the remaining arguments to be supplied. projections in q are of type `256h` (`100h` in hexadecimal)