Sunday, July 26, 2026

 A Critical Analysis of Artificial Intelligence and Life in 2030 from the Perspective of 2026


The 2016 Stanford AI100 report, Artificial Intelligence and Life in 2030 attempted forecasting the everyday impact of AI on a typical North American city over the next fifteen years. Now, ten years after publication and four years short of its target date, enough evidence exists to evaluate how its forecasts compare with reality. What emerges is a mixed picture. The report was extraordinarily accurate about the direction of AI development, the centrality of machine learning, the growing importance of data, and the rise of AI across transportation, healthcare, education, public safety, and entertainment. However, it significantly underestimated the speed and scale of generative AI, overestimated progress in physical robotics and autonomous vehicles, and only partially anticipated the political, economic, and cultural disruptions created by large foundation models. The report’s greatest success was identifying AI as an increasingly pervasive infrastructure technology; its greatest failure was not foreseeing that language and content generation would become the dominant public face of AI by 2026.


It correctly predicted the continuing dominance of machine learning and deep learning. In 2016, the authors identified large-scale machine learning, deep learning, natural language processing, reinforcement learning, computer vision, and collaborative human-AI systems as the major research frontiers. That assessment has proven highly accurate. The years since 2016 have seen deep learning become the foundation of virtually every major breakthrough in AI. The current AI landscape is dominated by systems trained on vast datasets using enormous computational resources, precisely the trend the report described. Its claim that AI research was shifting toward systems that collaborate effectively with humans has also proven correct. Today, AI is routinely used as a writing partner, coding assistant, research assistant, tutor, translator, customer-service agent, and creative collaborator. In that sense, the report correctly perceived that the future would not simply consist of autonomous machines replacing humans, but increasingly sophisticated partnerships between humans and AI systems.


Yet the report's account of natural language processing now appears surprisingly conservative. The authors expected dialogue systems to become more capable and machine translation to improve substantially. What they did not anticipate was the emergence of large language models capable of generating essays, software code, summaries, business reports, images, and conversational interactions at a level that would trigger widespread societal debate. The report discussed NLP as a promising subfield aimed at improving dialogue and speech recognition. By 2026, however, generative AI has become one of the defining technologies of the decade. Systems based on transformer architectures, foundation models, and large-scale pretraining have transformed industries ranging from software development to education and media production. This omission is understandable—transformers had not yet been introduced in 2016—but it remains the report's most significant forecasting gap.


Transportation illustrates the opposite pattern: the report accurately identified the direction of change but overestimated its pace. The authors predicted that autonomous transportation would become commonplace, that self-driving vehicles would significantly reshape urban life, and that ownership of personal cars might decline. They also suggested widespread deployment of autonomous trucks, delivery vehicles, and related robotic transport systems. By 2026, progress has been substantial but uneven. Driver-assistance systems have improved dramatically, robotaxi deployments exist in limited geographic areas, and autonomous vehicle technology has advanced far beyond what existed in 2016. However, self-driving transportation has not become commonplace across North American cities. Most people still drive conventional vehicles, urban design remains largely unchanged, parking infrastructure has not become obsolete, and broad public adoption has not occurred. The report underestimated the difficulty of solving edge cases, managing safety concerns, obtaining regulatory approval, and gaining public trust. Its prediction that flying vehicles and advanced autonomous transport would spread widely by 2030 increasingly appears optimistic. Interestingly, the report itself expressed skepticism regarding flying transportation platforms, and that caution now appears justified.


The report's treatment of robotics was generally more accurate than its transportation forecasts. It argued that home and service robots would expand slowly because hardware challenges are fundamentally more difficult than software challenges. This has proven correct. While AI software capabilities have exploded, domestic robotics has advanced incrementally. Robot vacuum cleaners have become more sophisticated, warehouses increasingly use robotic systems, and specialized industrial robots have proliferated. Yet there has been no mass-market revolution in general-purpose household robots. The report repeatedly emphasized that reliable mechanical systems remain expensive and difficult to develop. Ten years later, that observation remains valid.


Healthcare demonstrates another area where the report largely got the direction right while overestimating the speed of institutional adoption. The report envisioned AI-enhanced clinical decision support, improved medical imaging, patient monitoring, predictive analytics, and greater use of electronic health data. Many of these developments have indeed occurred. AI systems now assist with radiology, diagnostics, administrative workflows, transcription, medical documentation, and drug discovery. However, the report also noted that regulatory barriers, trust issues, fragmented data systems, and poor healthcare software infrastructure would impede deployment. Those obstacles remain significant. The prediction that AI would augment clinicians rather than replace them has been validated. Healthcare has become one of the strongest cases supporting the report's broader thesis that AI is more likely to transform tasks than eliminate entire professions.


Education presents a particularly interesting comparison between prediction and reality. The report anticipated greater personalization, intelligent tutoring systems, blended learning, online education, learning analytics, and AI-assisted teaching. All of these trends have emerged. However, once again, the arrival of generative AI changed the landscape in ways the report did not foresee. Rather than educational AI being dominated by tutoring software and learning management systems, students and teachers increasingly use conversational AI systems for writing assistance, research support, coding help, language learning, and individualized explanation generation. The report correctly predicted personalized learning but underestimated the degree to which a single general-purpose AI system could act simultaneously as tutor, encyclopedia, translator, writer, and research assistant.


Perhaps the report's most impressive achievement lies in its discussion of public policy and governance. The authors repeatedly warned that governments would need greater technical AI expertise, that questions of bias and fairness would become central, and that privacy, accountability, transparency, and equitable distribution of benefits would become major policy issues. This forecast has aged exceptionally well. Public debate over algorithmic bias, surveillance, AI safety, disinformation, intellectual property, concentration of power among technology firms, and the economic effects of automation has become central to AI governance worldwide. The report also anticipated concerns about AI amplifying existing inequalities and concentrating wealth among those who control data, computation, and AI infrastructure. Those concerns are now at the center of policy discussions across governments and industries.


Its predictions regarding employment were similarly nuanced. Rather than forecasting mass unemployment, the report argued that AI would primarily replace tasks rather than entire jobs in the short term. That remains broadly true in 2026. Although fears of immediate labor-market collapse have not materialized, AI is steadily reshaping knowledge work, software development, customer support, content creation, marketing, legal review, and administrative functions. The report also raised questions about wealth distribution and the possibility that AI could become a new mechanism for wealth creation concentrated among a small group of actors. A decade later, these concerns appear increasingly relevant.


The report's discussion of entertainment is another area where its predictions were broadly accurate. It correctly anticipated increasingly personalized, interactive, and AI-driven entertainment experiences. Recommendation systems, algorithmically curated content, virtual influencers, AI-generated music, AI-generated imagery, and synthetic media have become commonplace. Yet here, too, the authors underestimated the transformative potential of generative systems capable of creating content on demand. The concept of individuals producing sophisticated media through interaction with AI is now far more developed than the report envisioned.


In retrospect, the report's deepest insight was methodological rather than technological. It rejected the popular narrative of imminent superintelligence and focused instead on gradual, domain-specific, specialized AI systems integrated into everyday life. That judgment remains largely correct. Contrary to sensational fears, no self-aware superintelligence has emerged. AI's influence has spread through thousands of practical applications rather than through a single revolutionary machine. At the same time, the report underestimated how foundation models would unify many previously separate AI capabilities into versatile systems that appear general-purpose to ordinary users.


This report’s forecasts about the importance of machine learning, the growth of healthcare AI, personalized education, algorithmic governance, workplace transformation, and the need for thoughtful policy were largely vindicated. Its principal errors were forecasting too much progress in autonomous transportation and too little progress in generative AI. The report correctly identified most of the forces shaping the AI era but misjudged which applications would become culturally dominant first. From the vantage point of 2026, it stands as an unusually successful technological forecast—one whose omissions are notable precisely because so much else turned out to be right.


Reference: Artificial Intelligence and Life in 2030: https://arxiv.org/pdf/2211.06318 


Saturday, July 25, 2026

 

The Intelligence Explosion by James Barrat is a book that explores the rapid development of artificial intelligence (AI) and the possible consequences of creating machines that are smarter than humans. Barrat, a journalist and documentary filmmaker, examines both the exciting opportunities and the serious risks that advanced AI could bring to society.

 

He observes that AI technology is improving at an accelerating rate and discusses the possibility of an “intelligence explosion,” a situation in which an artificial intelligence becomes capable of improving itself. Once this happens, each improvement could help the machine make itself even smarter, leading to extremely rapid growth in intelligence. According to the author, such a system could eventually surpass human intelligence by a wide margin.

 

Throughout the book, Barrat interviews scientists, researchers, and technology experts who are working in the field of AI. Some of these experts are optimistic about the benefits of advanced AI, including medical breakthroughs, scientific discoveries, and solutions to major global problems. However, many also express concern about the risks. Barrat argues that if powerful AI systems are not properly designed, they may pursue goals that conflict with human values and interests.

 

He calls out the challenge of controlling highly intelligent machines. Barrat explains that a superintelligent AI might not be evil, but it could still cause harm if its objectives are not perfectly aligned with human needs. He emphasizes that humanity may not get a second chance if such a technology is created without adequate safeguards.

 

Another important message of the book is the need for careful planning and cooperation. Barrat encourages governments, researchers, and technology companies to think seriously about AI safety before creating increasingly powerful systems. He believes that society should prepare for the future rather than waiting until advanced AI already exists.

 

Finally, this book is a thought-provoking exploration of the future of artificial intelligence. James Barrat presents both the enormous promise and the potential dangers of machines that could exceed human intelligence. The book encourages readers to think critically about technological progress and the responsibilities that come with creating powerful new inventions. It serves as a warning that while AI could greatly benefit humanity, it must be developed with caution and foresight.


Thursday, July 23, 2026

Capstone exercise

 #Capstone Exercise: 

A capstone project is a comprehensive, culminating academic assignment that learners complete at the end of a course such as GenAI training. It requires you to apply the skills and knowledge you've acquired throughout your studies to investigate, design a solution for, or evaluate a specific, real-world problem or research question

This Capstone project demonstrates:

✅ Chroma vector store

✅ text-embedding-3-small embeddings

✅ GPT generation

✅ Semantic retrieval

✅ Semantic + threshold retrieval

✅ Hybrid retrieval (BM25 + semantic)

✅ Hallucination-resistant prompt

✅ No-answer fallback

✅ Top-K ≤ 3

✅ Outputs submission.csv


#!/usr/bin/python


import os

import json

import numpy as np

import pandas as pd


from dotenv import load_dotenv


from tenacity import (

    retry,

    stop_after_attempt,

    wait_random_exponential

)


from langchain_community.document_loaders import CSVLoader

from langchain_community.vectorstores import Chroma


from langchain_openai import (

    AzureOpenAIEmbeddings,

    AzureChatOpenAI

)


from rank_bm25 import BM25Okapi



# ============================================================

# CONFIGURATION

# ============================================================


load_dotenv("./Data/vars.env")


DATASET_FILE = "./Data/capstone1_rag_dataset.csv"

TEST_FILE = "./Data/capstone1_rag_test_questions.csv"


VECTOR_DB_DIR = "./chroma_capstone_db"


AZURE_OPENAI_ENDPOINT = os.environ["MODEL_ENDPOINT"]

OPENAI_API_VERSION = os.environ["API_VERSION"]

CHAT_DEPLOYMENT_NAME = os.environ["MODEL_NAME"]

PROJECT_ID = os.environ["PROJECT_ID"]


EMBEDDINGS_DEPLOYMENT_NAME = os.environ["EMBEDDINGS_DEPLOYMENT_NAME "]


# Required by Chroma in many enterprise environments

os.environ["ANONYMIZED_TELEMETRY"] = "False"



# ============================================================

# AUTHENTICATION

# ============================================================


def get_access_token():

    auth = "https://<your-provider-endpoint>/oauth2/token"

    scope = "https:// <your-provider-endpoint>/.default"

    grant_type = "client_credentials"



    with httpx.Client() as client:

        body = {

            "grant_type": grant_type,

            "scope": scope,

            "client_id": dbutils.secrets.get(scope="AIML_Training", key="client_id"),

            "client_secret": dbutils.secrets.get(scope="AIML_Training", key="client_secret"),

        }

        headers = {"Content-Type": "application/x-www-form-urlencoded"}

        resp = client.post(auth, headers=headers, data=body, timeout=60)

        access_token = resp.json()["access_token"]

        return access_token


# ============================================================

# MODELS

# ============================================================


embeddings = AzureOpenAIEmbeddings(

    azure_deployment=EMBEDDINGS_DEPLOYMENT_NAME,

    azure_endpoint=AZURE_OPENAI_ENDPOINT,

    api_version=OPENAI_API_VERSION,

    azure_ad_token_provider=get_access_token,

    default_headers={

        "projectId": PROJECT_ID,

        "model-usage-type": "prod"

    }

)


llm = AzureChatOpenAI(

    azure_deployment=CHAT_DEPLOYMENT_NAME,

    azure_endpoint=AZURE_OPENAI_ENDPOINT,

    api_version=OPENAI_API_VERSION,

    azure_ad_token_provider=get_access_token,

    default_headers={

        "projectId": PROJECT_ID,

        "model-usage-type": "prod"

    },

    temperature=0.1

)



# ============================================================

# DATA LOADING

# ============================================================


def load_dataset():


    loader = CSVLoader(

        file_path=DATASET_FILE,

        encoding="utf-8"

    )


    return loader.load()



# ============================================================

# VECTOR STORE

# ============================================================


@retry(

    wait=wait_random_exponential(min=2, max=30),

    stop=stop_after_attempt(5),

    reraise=True

)

def build_vector_store(documents):


    return Chroma.from_documents(

        documents=documents,

        embedding=embeddings,

        persist_directory=VECTOR_DB_DIR

    )



# ============================================================

# BM25 INDEX

# ============================================================


def build_bm25_index(documents):


    corpus = [

        doc.page_content

        for doc in documents

    ]


    tokenized = [

        text.lower().split()

        for text in corpus

    ]


    bm25 = BM25Okapi(tokenized)


    return bm25, corpus



# ============================================================

# RETRIEVAL STRATEGY #1

# Semantic Search

# ============================================================


def semantic_retrieval(

    query,

    vectorstore,

    top_k=3

):


    results = vectorstore.similarity_search(

        query,

        k=top_k

    )


    docs = [

        doc.page_content

        for doc in results

    ]


    return docs



# ============================================================

# RETRIEVAL STRATEGY #2

# Semantic + Threshold Filtering

# ============================================================


def threshold_retrieval(

    query,

    vectorstore,

    threshold=0.70,

    top_k=3

):


    try:


        results = vectorstore.similarity_search_with_relevance_scores(

            query,

            k=10

        )


        filtered_docs = []


        for doc, score in results:


            if score >= threshold:

                filtered_docs.append(

                    doc.page_content

                )


        return filtered_docs[:top_k]


    except Exception:


        return semantic_retrieval(

            query,

            vectorstore,

            top_k

        )



# ============================================================

# RETRIEVAL STRATEGY #3

# Hybrid BM25 + Semantic

# ============================================================


def hybrid_retrieval(

    query,

    vectorstore,

    bm25,

    corpus,

    top_k=3

):


    semantic_results = vectorstore.similarity_search(

        query,

        k=10

    )


    semantic_texts = {

        doc.page_content

        for doc in semantic_results

    }


    bm25_scores = bm25.get_scores(

        query.lower().split()

    )


    ranked_idx = np.argsort(

        bm25_scores

    )[::-1][:10]


    bm25_texts = {

        corpus[idx]

        for idx in ranked_idx

    }


    combined_docs = list(

        semantic_texts.union(

            bm25_texts

        )

    )


    scored_docs = []


    query_embedding = embeddings.embed_query(

        query

    )


    for doc_text in combined_docs:


        try:


            doc_embedding = embeddings.embed_query(

                doc_text[:8000]

            )


            cosine = np.dot(

                query_embedding,

                doc_embedding

            ) / (

                np.linalg.norm(query_embedding)

                * np.linalg.norm(doc_embedding)

            )


            scored_docs.append(

                (

                    doc_text,

                    float(cosine)

                )

            )


        except Exception:

            pass


    scored_docs.sort(

        key=lambda x: x[1],

        reverse=True

    )


    return [

        doc

        for doc, _

        in scored_docs[:top_k]

    ]



# ============================================================

# GENERATION

# ============================================================


@retry(

    wait=wait_random_exponential(min=2, max=30),

    stop=stop_after_attempt(5),

    reraise=True

)

def generate_answer(

    query,

    retrieved_docs

):


    if len(retrieved_docs) == 0:


        return (

            "The question cannot be answered "

            "using the available documents."

        )


    context = "\n\n".join(

        retrieved_docs

    )


    prompt = f"""

You are a clinical intelligence assistant.


IMPORTANT RULES:


1. Use ONLY the provided context.

2. Do NOT use prior medical knowledge.

3. Do NOT hallucinate.

4. If the answer is not present in the context,

   say:

   "The question cannot be answered using the available documents."

5. Cite information only from context.

6. Keep responses concise and factual.


CONTEXT:


{context}


QUESTION:


{query}


ANSWER:

"""


    response = llm.invoke(

        prompt

    )


    return response.content



# ============================================================

# MAIN RAG PIPELINE

# ============================================================


def rag_pipeline(

    query,

    vectorstore,

    bm25,

    corpus,

    retrieval_strategy="hybrid"

):


    if retrieval_strategy == "semantic":


        docs = semantic_retrieval(

            query,

            vectorstore

        )


    elif retrieval_strategy == "threshold":


        docs = threshold_retrieval(

            query,

            vectorstore

        )


    else:


        docs = hybrid_retrieval(

            query,

            vectorstore,

            bm25,

            corpus

        )


    answer = generate_answer(

        query,

        docs

    )


    return {

        "retrieved_documents": docs,

        "generated_answer": answer

    }



# ============================================================

# MAIN

# ============================================================


if __name__ == "__main__":


    print("Loading dataset...")


    documents = load_dataset()


    print(

        f"Documents Loaded: {len(documents)}"

    )


    print("Building vector store...")


    vectorstore = build_vector_store(

        documents

    )


    print("Building BM25 index...")


    bm25, corpus = build_bm25_index(

        documents

    )


    print("Loading questions...")


    questions_df = pd.read_csv(

        TEST_FILE,

        dtype=str

    ).fillna("")


    questions_df[

        "retrieved_documents"

    ] = ""


    questions_df[

        "generated_answer"

    ] = ""


    for idx, row in questions_df.iterrows():


        question = row["question"]


        print("\n" + "=" * 80)

        print(

            f"QUESTION {idx + 1}:"

        )

        print(question)


        result = rag_pipeline(

            query=question,

            vectorstore=vectorstore,

            bm25=bm25,

            corpus=corpus,

            retrieval_strategy="hybrid"

        )


        print("\nANSWER:")

        print(

            result["generated_answer"]

        )


        questions_df.loc[

            idx,

            "retrieved_documents"

        ] = json.dumps(

            result[

                "retrieved_documents"

            ]

        )


        questions_df.loc[

            idx,

            "generated_answer"

        ] = result[

            "generated_answer"

        ]


    submission = questions_df[

        [

            "question",

            "retrieved_documents",

            "generated_answer"

        ]

    ]


    submission.to_csv(

        "submission.csv",

        index=False

    )


    print("\nsubmission.csv created.")

    print(

        f"Rows: {len(submission)}"

    )

 # ============================================================

# SAMPLE OUTPUT

# ============================================================

Loading dataset...

Creating vector store...

Failed to send telemetry event ClientStartEvent: capture() takes 1 positional argument but 3 were given

Failed to send telemetry event ClientCreateCollectionEvent: capture() takes 1 positional argument but 3 were given

Loading questions...

Processing: What are the key features of …

Failed to send telemetry event CollectionQueryEvent: capture() takes 1 positional argument but 3 were given

document_id: 94

document_url: https://...

context: Auto…

---

document_id: 769

document_url: https://...

context: Palm…

---

document_id: 784

document_url: https://...

context: La...

  questions_df.loc[idx, "retrieved_documents"]


  questions_df.loc[idx, "generated_answer"]



Wednesday, July 22, 2026

 Introduction

In his satirical short story collection, Abschalten: Die Business Class macht Ferien (translated as Switching Off: The Business Class Takes a Vacation), Swiss author Martin Suter explores the psychological shortcomings of modern corporate culture. The book focuses on middle management corporate workers. These characters are constantly drained by corporate strategies, workplace rivalries, and endless meetings. Suter uses humor to show what happens when workaholics are forced to take a vacation. Instead of relaxing, they find themselves unable to escape their corporate mindsets. 

Plot Summary and Core Themes

The book consists of over 50 short stories. Each story details the vacation struggles of different corporate managers. The plot moves from the stressful office environment to luxury holiday destinations. Instead of resting, the characters treat their time off like business projects. They attempt to micromanage their families, schedule their relaxation down to the minute, and optimize their leisure time. 

Suter highlights a major thematic conflict: the absolute fear of being useless. For these corporate leaders, a successful vacation is terrifying because it means the company can run without them. To cope, some managers delay their trips, leave early, or find ways to stay constantly tethered to smartphones and laptops. The stories highlight how deep work obsessions can run, showing that corporate habits often destroy personal lives and family time. 

Character Analysis

The characters in Suter's stories, carrying common corporate names like Huber, Lindner, and Glaser, serve as representations of the modern white-collar worker. They lack distinct individual identities. Instead, they are defined entirely by their job titles and status symbols. For instance, the character Glaser attempts to use specialized therapies and medical treatments just to find a mental "off-switch," only to realize his identity is completely dependent on work stress. The characters are blind to their own absurdity, making them both targets for satire and tragic examples of modern burnout. 

Style and Satirical Elements

Suter utilizes a detached, sharp narrative voice that mirrors the language of corporate memos and performance reviews. This stylistic choice emphasizes the comedy, as intimate family interactions are described using corporate buzzwords like "synergy," "quality time," and "efficiency". The repetitive structure of the stories reinforces the idea that these managers are stuck in an endless loop of work stress. 

Conclusion

Ultimately, Abschalten serves as a warning about work culture. Suter suggests that the modern business world strips people of their ability to experience simple human joy. By turning vacations into business operations, the characters reveal a deeper societal issue: the loss of personal identity outside of employment. The book leaves readers with a clear takeaway: if you cannot turn off your work brain, you will eventually lose your freedom. 



Monday, July 20, 2026

 Fourier Transformations for wave propagation:

Introduction: A Fast Fourier Transform converts wave form data in the time domain into the frequency domain. It achieves this by breaking down the original time-based waveform into a series of sinusoidal terms, each with a unique magnitude, frequency and phase. This process converts a waveform in the time domain into a series of sinusoidal functions which when added together reconstruct the original waveform. Plotting the amplitude of each sinusoidal term versus its frequency creates a power spectrum, which is the response of the original waveform in the frequency domain.


When Fourier transforms are applicable, it means the “earth response” now is the same as the “earth response” later. Switching our point of view from time to space, the applicability of the Fourier transformation means that the “impulse response” here is the same as the “impulse response” there. An impulse is a column vector full of zeros with somewhere a one. An impulse response is a column from the matrix q = Bp The collection of impulse responses in q=Bp defines the convolution operation.


Sample FFT application:

import numpy as nm

import scipy

import scipy.fftpack

import pylab


def lowpass_cosine( y, tau, f_3db, width, padd_data=True):

    # padd_data = True means we are going to symmetric copies of the data to the start and stop

    # to reduce/eliminate the discontinuities at the start and stop of a dataset due to filtering

    #

    # False means we're going to have transients at the start and stop of the data


    # kill the last data point if y has an odd length

    if nm.mod(len(y),2):

        y = y[0:-1]


    # add the weird padd

    # so, make a backwards copy of the data, then the data, then another backwards copy of the data

    if padd_data:

        y = nm.append( nm.append(nm.flipud(y),y) , nm.flipud(y) )


    # take the FFT

    ffty=scipy.fftpack.fft(y)

    ffty=scipy.fftpack.fftshift(ffty)


    # make the companion frequency array

    delta = 1.0/(len(y)*tau)

    nyquist = 1.0/(2.0*tau)

    freq = nm.arange(-nyquist,nyquist,delta)

    # turn this into a positive frequency array

    pos_freq = freq[(len(ffty)/2):]


    # make the transfer function for the first half of the data

    i_f_3db = min( nm.where(pos_freq >= f_3db)[0] )

    f_min = f_3db - (width/2.0)

    i_f_min = min( nm.where(pos_freq >= f_min)[0] )

    f_max = f_3db + (width/2);

    i_f_max = min( nm.where(pos_freq >= f_max)[0] )


    transfer_function = nm.zeros(len(y)/2)

    transfer_function[0:i_f_min] = 1

    transfer_function[i_f_min:i_f_max] = (1 + nm.sin(-nm.pi * ((freq[i_f_min:i_f_max] - freq[i_f_3db])/width)))/2.0

    transfer_function[i_f_max:(len(freq)/2)] = 0


    # symmetrize this to be [0 0 0 ... .8 .9 1 1 1 1 1 1 1 1 .9 .8 ... 0 0 0] to match the FFT

    transfer_function = nm.append(nm.flipud(transfer_function),transfer_function)


    # plot up the transfer function

    # since "freq" is only the positive frequencies, select out

    pylab.figure(1)

    pylab.clf()

    pylab.plot(freq,transfer_function)

    pylab.xlabel('Frequency [Hz]')

    pylab.ylabel('Filter Transfer Function')

    pylab.xlim([-10.0,10.0])

    pylab.ylim([-0.05,1.05])


    # apply the filter, undo the fft shift, and invert the fft

    filtered=nm.real(scipy.fftpack.ifft(scipy.fftpack.ifftshift(ffty*transfer_function)))


    # remove the padd, if we applied it

    if padd_data:

        filtered = filtered[(len(y)/3):(2*(len(y)/3))]


    # return the filtered data

    return filtered



# do an example of lowpass filtering

# first make some fake data

# a sine wave fluctuating once every pi seconds

# samples 1000 times per second

fakedata = nm.sin(nm.arange(0,11,0.001)) + nm.random.randn(len(nm.arange(0,11,0.001)))/4.0


# run the filter

# lowpass at 5 Hz, with a 1 Hz width of its roll-off

filtered = lowpass_cosine(fakedata,0.001,5.0,1.0,padd_data=True)


# plot the noisy data, with the filtered data on top

pylab.figure(2)

pylab.clf()

pylab.plot(nm.arange(0,11,0.001),fakedata,label='Noisy Data')

pylab.plot(nm.arange(0,11,0.001),filtered,label='Lowpass Filtered Data')

pylab.xlabel('Time [s]')

pylab.ylabel('Voltage')

pylab.legend()


pylab.ion()

pylab.show()


References: Drone Video Sensing Application: https://github.com/ravibeta/dvsa-api/ 


Sunday, July 19, 2026

 Generative artificial intelligence is becoming a normal part of modern software, business workflows, and digital operations, but its usefulness depends on disciplined risk management. These systems should not be treated as ordinary web tools or simple productivity aids. They can process prompts, files, code, credentials, customer records, business plans, and other sensitive inputs; they can also return generated text, code, links, recommendations, or automated actions that may be incomplete, unsafe, or difficult to verify. Because these systems often appear through many access paths, including public websites, desktop applications, browser extensions, programming interfaces, embedded application features, marketplace plugins, and integrations with managed or unmanaged devices, organizations need a clear operating model before broad adoption becomes uncontrolled use.

A practical way to understand this environment is to classify generative applications by their approval status and security posture. Some tools are formally approved, managed, and governed by the organization. Others are tolerated for limited business needs even though they are not centrally owned, and they require constraints around users, data types, and permitted tasks. A third group consists of unapproved tools used without oversight, which creates the greatest exposure because the organization may not know what data is being submitted, where it is stored, who can access it, or whether it may be used to improve external models. This classification is not merely administrative. It determines how identity controls, network policy, logging, monitoring, data protection, and user training should be applied.

The first major risk is lack of visibility. When employees adopt generative tools independently, security and engineering teams may lose the ability to observe data flows, inspect usage patterns, or detect risky behavior. This “shadow” usage can result in sensitive source code, internal design notes, customer information, intellectual property, credentials, or regulated data being sent to systems that were never reviewed. Visibility must therefore extend beyond traditional application inventories. It should include browser-based access, installed applications, plugins, embedded features inside existing platforms, application programming interface calls, and connections from both managed and unmanaged endpoints. Without this baseline, an organization cannot make reliable decisions about which tools to allow, restrict, or block.

The second major risk is weak access control. Generative systems can amplify the consequences of excessive permissions because they make it easier to summarize, transform, export, or combine information at scale. If every user in a department can submit sensitive datasets or retrieve generated analysis without role-based limits, the tool may become a path for accidental disclosure or misuse. Access should be granular, based on job function, business need, data sensitivity, device posture, and application category. Approved tools may be broadly available under controlled conditions, tolerated tools may be limited to specific teams and use cases, and unapproved tools should be blocked or isolated when they create unacceptable risk. These controls should be reviewed regularly because both business needs and application behavior change quickly.

The third major risk is unsafe generated content. A model can produce code that appears correct but contains insecure dependencies, flawed authorization checks, injection vulnerabilities, or licensing concerns. It can also generate links, scripts, configuration suggestions, or operational instructions that users may trust too readily. Engineering teams should treat generated output as untrusted until it has been reviewed, tested, and validated through normal secure development practices. This includes static analysis, dependency scanning, code review, threat modeling, test coverage, and careful handling of generated commands or infrastructure changes. Training is important because many failures occur not from malicious intent but from misplaced confidence in fluent output.

Plugins and integrations require special attention because they can expand an application’s effective permissions beyond what users recognize. A plugin may read messages, files, tickets, repositories, calendars, customer records, or other enterprise data, and it may continue to operate through delegated permissions or service accounts. Marketplace availability does not imply that a plugin is safe for a particular organization. Each integration should be evaluated for requested permissions, authentication method, data access scope, logging behavior, retention practices, and administrative ownership. Service accounts and application credentials should follow least-privilege principles, be rotated when appropriate, and be monitored for anomalous behavior. Blocking direct access to a parent application is not sufficient if related plugins or embedded capabilities can still reach sensitive data.

Data at rest is another important concern. Sensitive information may accumulate inside generative applications through prompts, uploaded files, conversation history, cached responses, logs, embeddings, or connected data stores. If retained data is not discovered and governed, it can create compliance, privacy, and intellectual property exposure. Organizations should identify what information is stored, how long it persists, who can access it, whether it can be exported, and whether it is used for model improvement or downstream processing. Data discovery and remediation should include both approved and tolerated systems, because risk is often created by ordinary usage patterns rather than obvious policy violations.

A balanced governance model avoids two common mistakes. One mistake is allowing uncontrolled adoption because the productivity benefits seem immediate. The other is applying overly broad restrictions that block useful work and drive employees toward less visible alternatives. Effective governance enables safe use by combining discovery, classification, access control, data inspection, monitoring, and education. Data loss prevention policies should inspect outbound information based on sensitivity and context, not just keywords. Rules should account for source code, secrets, personal information, regulated records, confidential plans, and proprietary documents. They should also evolve as new applications, data types, and attack patterns emerge.

Continuous monitoring is essential because generative AI adoption changes faster than many traditional software programs. Security teams should maintain an inventory of tools in use, observe traffic and data flows, detect newly introduced plugins or automated agents, review changes in application permissions, and alert on policy violations or unusual activity. Risk assessment should be recurring rather than one time. It should consider who is using a tool, what data is being submitted, what outputs are produced, whether the tool interacts with internal systems, and whether the use case aligns with organizational policy. For engineering organizations, this monitoring should be integrated with existing secure software development, identity governance, endpoint management, and incident response processes.

Employee education should be practical and role specific. Developers need guidance on reviewing generated code, protecting secrets, avoiding sensitive prompts, and validating third-party packages. Product and design teams need guidance on responsible use of customer data and internal strategy documents. Support, sales, finance, human resources, and operations teams need clear examples of what information may or may not be submitted to generative systems. Training should be reinforced through timely prompts, notifications, and approved alternatives so that users are guided toward safe behavior at the moment they are making decisions.

Success should be measured with both productivity and protection in mind. Useful metrics include adoption of approved tools, reduction in unapproved usage, fewer data exposure incidents, improved response to policy violations, employee satisfaction with available tools, time saved in common workflows, and evidence that generated outputs are being reviewed appropriately. These measures help leaders determine whether controls are enabling responsible use rather than merely restricting activity. A mature program treats generative AI as part of the broader software and data ecosystem: powerful, useful, and increasingly embedded, but requiring explicit design for security, privacy, reliability, and accountability. With clear classification, least-privilege access, strong data controls, continuous monitoring, and practical user education, organizations can benefit from generative AI while reducing the likelihood that productivity gains become security liabilities.

#codingexercise: Codingexercise-07-19-2026.docx


Saturday, July 18, 2026

 Given two strings s and t, both consisting of lowercase English letters and digits, your task is to calculate how many ways exactly one digit could be removed from one of the strings so that s is lexicographically smaller than t after the removal. Note that we are removing only a single instance of a single digit, rather than all instances (eg: removing 1 from the string a11b1c could result in a1b1c or a11bc, but not abc).

Also note that digits are considered lexicographically smaller than letters.

Example

• For s = "ab12c" and t = "1zz456", the output should be solution(s, t) = 1.

Here are all the possible removals:

o We can remove the first digit from s, obtaining "ab2c". "ab2c" > "1zz456", so we don't count this removal

o We can remove the second digit from s, obtaining "ab1c". "ab1c" > "1zz456", so we don't count this removal

o We can remove the first digit from t, obtaining "zz456". "ab12c" < "zz456", so we count this removal

o We can remove the second digit from t, obtaining "1zz56". "ab12c" > "1zz56", so we don't count this removal

o We can remove the third digit from t, obtaining "1zz46". "ab12c" > "1zz46", so we don't count this removal

o We can remove the fourth digit from t, obtaining "1zz45". "ab12c" > "1zz45", so we don't count this removal

The only valid case where s < t after removing a digit is "ab12c" < "zz456". Therefore, the answer is 1.

• For s = "ab12c" and t = "ab24z", the output should be solution(s, t) = 3.

There are 4 possible ways of removing the digit:

o "ab1c" < "ab24z"

o "ab2c" > "ab24z"

o "ab12c" < "ab4z"

o "ab12c" < "ab2z"

Three of these cases match the requirement that s < t, so the answer is 3.

Input/Output

• [execution time limit] 3 seconds (java)

• [input] string s

A string consisting of lowercase English letters and digits 0..9.

Guaranteed constraints:

1 ≤ s.length ≤ 103.

• [input] string t

A string consisting of lowercase English letters and digits 0..9.

Guaranteed constraints:

1 ≤ t.length ≤ 103.

• [output] integer

The number of ways to remove exactly one digit from one of the strings so that s is lexicographically smaller than t after the removal.

 Java solution:

int solution(String s, String t) {

    int count = 0;

    for (int i = 0; i < s.length(); i++){

        if (s.charAt(i) >= '0' && s.charAt(i) <= '9') {

            String u = (i-1 >= 0 ? s.substring(0, i) : "") + (i+1 < s.length() ? s.substring(i+1, s.length()) : "");

            //// System.out.println(u + " " + t);

            if (lessThan(u,t)) {

                count++;

            } 

        }    

    }

    

    for (int j = 0; j < t.length(); j++) {

        if (t.charAt(j) >= '0' && t.charAt(j) <= '9') {

            String u = (j-1 >= 0 ? t.substring(0, j) : "") + (j+1 < t.length() ? t.substring(j+1, t.length()) : "");

            ///// System.out.println(s + " " + u);

            if (lessThan(s,u)) {

                count++;

            } 

        }

    }

    

    return count;

}


void print(String s, String t) {

    List<String> r = new ArrayList<String>();

    r.add(s);

    r.add(t);

    Collections.sort(r);

    System.out.println(Arrays.toString(r.toArray()));

}


boolean lessThan(String s, String t) {

    List<String> r = new ArrayList<String>();

    r.add(s);

    r.add(t);

    Collections.sort(r);

    return r.get(0).equals(s);

}

 Kotlin solution:

import java.util.Collections;

fun main() {

    println(solution("ab12c", "1zz456"));

}

fun solution(s: String, t: String): Int {

    var count = 0;

    for (i in 0..s.length-1){

        if (s[i] >= '0' && s[i] <= '9') {

            var u = "";

            if (i-1 >= 0) {

                u += s.substring(0..i-1);

   }

            if (i+1 < s.length) {

                u += s.substring((i+1)..s.length-1);

            }

            println(u + " " + t);

            if (lessThan(u,t)) {

                count++;

            } 

        }    

    }

    for (j in 0..t.length-1) {

        if (t[j] >= '0' && t[j] <= '9') {

            var u = "";

            if (j-1 >= 0) {

                u += t.substring(0..j-1);

   }

            if (j+1 < t.length) {

                u += t.substring((j+1)..t.length-1);

            }

            println(s + " " + u);

            if (lessThan(s,u)) {

                count++;

            } 

        }

    }

    return count;

}

fun lessThan(s: String, t: String) : Boolean {

    var r = ArrayList<String>();

    r.add(s);

    r.add(t);

    Collections.sort(r);

    return r.get(0).equals(s);

}


 Test 1:

Input:

s: "ab12c"

t: "1zz456"

Output:

1

Expected Output:

1

Console Output:

ab2c 1zz456

ab1c 1zz456

ab12c zz456

ab12c 1zz56

ab12c 1zz46

ab12c 1zz45

Error Output:

Empty


Test 2:

Input:

s: "ab12c"

t: "ab24z"

Output:

3

Expected Output:

3

Console Output:

ab2c ab24z

ab1c ab24z

ab12c ab4z

ab12c ab2z

Error Output:

Empty


Test 3:

Input:

s: "96726"

t: "9z34c"

Output:

8

Expected Output:

8

Console Output:

6726 9z34c

9726 9z34c

9626 9z34c

9676 9z34c

9672 9z34c

96726 z34c

96726 9z4c

96726 9z3c

Error Output:

Empty


Test 4:

Input:

s: "4u05q"

t: "ed0r7"

Output:

4

Expected Output:

4

Console Output:

u05q ed0r7

4u5q ed0r7

4u0q ed0r7

4u05q edr7

4u05q ed0r

Error Output:

Empty


Test 5:

Input:

s: "6"

t: "h"

Output:

1

Expected Output:

1

Console Output:

 h

Error Output:

Empty


Problem 2:

You are given an array of integers a, where each element a[i] represents the length of a ribbon.

Your goal is to obtain k ribbons of the same length, by cutting the ribbons into as many pieces as you want.

Your task is to calculate the maximum integer length L for which it is possible to obtain at least k ribbons of length L by cutting the given ones.

Example

• For a = [5, 2, 7, 4, 9] and k = 5, the output should be solution(a, k) = 4.

 

Here's a way to achieve 5 ribbons of length 4:

o Cut the ribbon of length 5 into one ribbon of length 1 (which can be discarded) and one ribbon of length 4.

o Cut the ribbon of length 7 into one ribbon of length 3 (which can be discarded) and one ribbon of length 4.

o Use the existing ribbon of length 4 (no need to cut it)

o Cut the ribbon of length 9 into two ribbons of length 4 (and one of length 1 which can be discarded)

o Discard the ribbon of length 2.

And since it wouldn't be possible to make 5 ribbons of any greater length, the answer is 4.

• For a = [1, 2, 3, 4, 9] and k = 6, the output should be solution(a, k) = 2.

Here's one way we could make 6 ribbons of length 2:

o Cut the ribbon of length 9 into four ribbons of length 2 and one ribbon of length 1 (which won't be used).

o Cut the ribbon of length 4 into two ribbons of length 2.

o Ignore all other ribbons (1, 2, and 3). Even though ribbons with lengths 2 and 3 can also be used to obtain the ribbon of length 2, we don't need more than 6 ribbons of that length.

It would technically be possible to make 6 ribbons of a length as great as 2.25, but since only integer values are allowed, the answer is 2.

Input/Output

• [execution time limit] 3 seconds (java)

• [input] array.integer a

An array of the ribbons' lengths.

Guaranteed constraints:

1 ≤ a.length ≤ 105,

1 ≤ a[i] ≤ 109.

• [input] integer k

The number of equal-length ribbons you need to obtain. It is guaranteed that it is possible to obtain this number of ribbons from the values in a.

Guaranteed constraints:

1 ≤ k ≤ min(sum(a[i]), 109).

• [output] integer

The maximum possible length of the obtained k ribbons.


Solution 2:

Java solution:

int solution(int[] a, int k) {

var max = Arrays.stream(a).max().getAsInt();

for (int i = 1; i <= max; i++) {

    int count = 0;

    for (int j = 0; j < a.length; j++) {

        if (a[j] >= i) {

            count += a[j] / i;

        }

    }

    if (count < k) {

        return i-1;

    }    

}

return max;

}

Kotlin solution:

fun ribbons(a: IntArray, k: Int): Int {

var max = Arrays.stream(a).max().getAsInt();

for (i in 1..max) {

    var count = 0;

    for (j in 0..a.size-1) {

        if (a[j] >= i) {

            count += a[j] / i;

        }

    }

    if (count < k) {

        return i-1;

    }    

}

return max;

}


Test Case 1:

Input:

a: [5, 2, 7, 4, 9]

k: 5

Output:

4

Expected Output:

4

Console Output:

Empty

Error Output:

Empty


Test Case 2:

Input:

a: [1, 2, 3, 4, 9]

k: 6

Output:

2

Expected Output:

2

Console Output:

Empty

Error Output:

Empty


Test Case 3:

Input:

a: [1, 2, 3, 4, 9]

k: 5

Output:

3

Expected Output:

3

Console Output:

Empty

Error Output:

Empty


Test Case 4:

Input:

a: [8, 4, 2, 6, 1, 2, 1, 7]

k: 14

Output:

2

Expected Output:

2

Console Output:

Empty

Error Output:

Empty


Test Case 5:

Input:

a: [4, 8, 4, 5, 3, 7, 1, 2, 6]

k: 5

Output:

4

Expected Output:

4

Console Output:

Empty

Error Output:

Empty